@@ -8,7 +8,28 @@ import fs from 'node:fs';
88import path from 'node:path' ;
99import { Org , SfError } from '@salesforce/core' ;
1010import axios from 'axios' ;
11+ import { PromptUtils } from '../promptUtils.js' ;
1112
13+ // TODO this format is what we want to be storing for each site
14+ export type NewSiteMetadata = {
15+ name : string ;
16+ siteZip : string ; // TODO do we want to store a list of ordered zip files we've downloaded? or just the most recent
17+ lastModified : Date ;
18+ coreVersion : string ;
19+ needsUpdate : boolean ;
20+ users : AuthUserMap ;
21+ } ;
22+
23+ export type AuthUserMap = {
24+ [ username : string ] : AuthToken ;
25+ } ;
26+
27+ export type AuthToken = {
28+ token : string ;
29+ issued : Date ;
30+ } ;
31+
32+ // This is what we have been storing in the sites.json
1233export type SiteMetadata = {
1334 bundleName : string ;
1435 bundleLastModified : string ;
@@ -33,16 +54,95 @@ export class ExperienceSite {
3354 public siteName : string ;
3455 private org : Org ;
3556 private metadataCache : SiteMetadataCache = { } ;
57+ private config ;
3658
3759 public constructor ( org : Org , siteName : string ) {
3860 this . org = org ;
3961 this . siteDisplayName = siteName . trim ( ) ;
4062 this . siteName = this . siteDisplayName . replace ( ' ' , '_' ) ;
4163 // Replace any special characters in site name with underscore
4264 this . siteName = this . siteName . replace ( / [ ^ a - z A - Z 0 - 9 ] / g, '_' ) ;
65+
66+ // Backwards Compat
67+ if ( process . env . SITE_GUEST_ACCESS === 'true' ) {
68+ process . env . PREVIEW_USER = 'Guest' ;
69+ }
70+ if ( process . env . SID_TOKEN && ! process . env . PREVIEW_USER ) {
71+ process . env . PREVIEW_USER = 'Custom' ;
72+ }
73+
74+ // TODO the config handling code should move into its own file
75+ // Store variables in consumable config to limit use of env variables
76+ // Eventually these will be part of CLI interface or scrapped in favor of config
77+ // once they are no longer experimental
78+ this . config = {
79+ previewUser : process . env . PREVIEW_USER ?? 'Admin' ,
80+ previewToken : process . env . SID_TOKEN ?? '' ,
81+ apiStaticMode : process . env . API_STATIC_MODE === 'true' ? true : false ,
82+ apiBundlingGroups : process . env . API_BUNDLING_GROUPS === 'true' ? true : false ,
83+ apiVersion : process . env . API_VERSION ?? 'v64.0' ,
84+ apiSiteVersion : process . env . API_SITE_VERSION ?? 'published' ,
85+ } ;
86+ }
87+
88+ public get apiQueryParams ( ) : string {
89+ const retVal = [ ] ;
90+
91+ // Preview is default. If we specify another mode, add it as a query parameter
92+ if ( this . config . apiSiteVersion !== 'preview' ) {
93+ retVal . push ( this . config . apiSiteVersion ) ;
94+ }
95+
96+ // Bundling groups are off by default. Only add if enabled
97+ if ( this . config . apiBundlingGroups ) {
98+ retVal . push ( 'bundlingGroups' ) ;
99+ }
100+
101+ // Metrics - TODO
102+
103+ // If we have query parameters, return them
104+ if ( retVal . length ) {
105+ return '?' + retVal . join ( '&' ) ;
106+ }
107+
108+ // Otherwise just return an empty string
109+ return '' ;
43110 }
44111
45112 /**
113+ * TODO this should use the connect api `{{orgInstance}}/services/data/v{{version}}/connect/communities`
114+ * Returns array of sites like:
115+ * communities[
116+ * {
117+ "allowChatterAccessWithoutLogin": true,
118+ "allowMembersToFlag": false,
119+ "builderBasedSnaEnabled": true,
120+ "builderUrl": "https://orgfarm-656f3290cc.test1.my.pc-rnd.salesforce.com/sfsites/picasso/core/config/commeditor.jsp?siteId=0DMSG000001lhVa",
121+ "contentSpaceId": "0ZuSG000001n1la0AA",
122+ "description": "D2C Codecept Murazik",
123+ "guestMemberVisibilityEnabled": false,
124+ "id": "0DBSG000001huWE4AY",
125+ "imageOptimizationCDNEnabled": true,
126+ "invitationsEnabled": false,
127+ "knowledgeableEnabled": false,
128+ "loginUrl": "https://orgfarm-656f3290cc.test1.my.pc-rnd.site.com/d2cbernadette/login",
129+ "memberVisibilityEnabled": false,
130+ "name": "D2C Codecept Murazik",
131+ "nicknameDisplayEnabled": true,
132+ "privateMessagesEnabled": false,
133+ "reputationEnabled": false,
134+ "sendWelcomeEmail": true,
135+ "siteAsContainerEnabled": true,
136+ "siteUrl": "https://orgfarm-656f3290cc.test1.my.pc-rnd.site.com/d2cbernadette",
137+ "status": "Live",
138+ "templateName": "D2C Commerce (LWR)",
139+ "url": "/services/data/v64.0/connect/communities/0DBSG000001huWE4AY",
140+ "urlPathPrefix": "d2cbernadettevforcesite"
141+ },
142+ ...
143+ ]
144+ *
145+ *
46146 * Fetches all current experience sites
47147 *
48148 * @param {Connection } conn - Salesforce connection object.
@@ -66,25 +166,37 @@ export class ExperienceSite {
66166 * @returns sid token for proxied site requests
67167 */
68168 public async setupAuth ( ) : Promise < string > {
69- let sidToken = '' ;
70- // Default to guest user access if specified
71- if ( process . env . SITE_GUEST_ACCESS === 'true' ) return sidToken ;
169+ const previewUser = this . config . previewUser . toLocaleLowerCase ( ) ;
72170
73- // Use a provided token if specified in environment variables
74- if ( process . env . SID_TOKEN ) return process . env . SID_TOKEN ;
171+ // Preview as Guest User (no token)
172+ if ( previewUser === 'guest' ) return '' ;
75173
76- // Otherwise attempt to generate one based on the currently authenticated admin user
77- try {
78- const networkId = await this . getNetworkId ( ) ;
79- sidToken = await this . getNewSidToken ( networkId ) ;
80- } catch ( e ) {
81- // eslint-disable-next-line no-console
82- console . error ( 'Failed to establish authentication for site' , e ) ;
174+ // Preview with supplied user token
175+ if ( this . config . previewToken ) return this . config . previewToken ;
176+
177+ // Preview as CLI Admin user (Default)
178+ if ( previewUser === 'admin' ) {
179+ try {
180+ const networkId = await this . getNetworkId ( ) ;
181+ const sidToken = await this . getNewSidToken ( networkId ) ;
182+ return sidToken ;
183+ } catch ( e ) {
184+ // eslint-disable-next-line no-console
185+ console . error ( 'Failed to establish authentication for site' , e ) ;
186+ }
83187 }
84188
189+ // TODO Check local metadata for token, if it doesn't exist, prompt the user
190+
191+ // Prompt user for token or re-use token already saved for the site
192+ const sidToken = await PromptUtils . promptUserForAuthToken ( ) ;
193+
194+ // TODO If are supplied a token, we should store it in the local metadata to reuse later on
195+
85196 return sidToken ;
86197 }
87198
199+ // TODO this doesn't work anymore, we should consider alternative strategies
88200 public async isUpdateAvailable ( ) : Promise < boolean > {
89201 const localMetadata = this . getLocalMetadata ( ) ;
90202 if ( ! localMetadata ) {
@@ -148,6 +260,7 @@ export class ExperienceSite {
148260 return siteJson ;
149261 }
150262
263+ // TODO rename to getStaticResourceMetadata()
151264 public async getRemoteMetadata ( ) : Promise < SiteMetadata | undefined > {
152265 if ( this . metadataCache . remoteMetadata ) return this . metadataCache . remoteMetadata ;
153266 const result = await this . org
@@ -197,7 +310,7 @@ export class ExperienceSite {
197310 */
198311 public async downloadSite ( ) : Promise < string > {
199312 let retVal ;
200- if ( process . env . STATIC_MODE !== 'true' ) {
313+ if ( ! this . config . apiStaticMode ) {
201314 // Use sites API to download the site bundle on demand
202315 retVal = await this . downloadSiteApi ( ) ;
203316 } else {
@@ -225,6 +338,8 @@ export class ExperienceSite {
225338
226339 // Download the site via API
227340 const conn = this . org . getConnection ( ) ;
341+
342+ // TODO update to the new metadata format
228343 const metadata = {
229344 bundleName : theSite . Name ,
230345 bundleLastModified : theSite . LastModifiedDate ,
@@ -239,12 +354,7 @@ export class ExperienceSite {
239354 }
240355 const resourcePath = this . getSiteZipPath ( metadata ) ;
241356 try {
242- // Limit API to published sites for now until we have a patch for the issues with unpublished sites
243- // TODO switch api back to preview mode after issues are addressed
244- let apiUrl = `${ instanceUrl } /services/data/v63.0/sites/${ siteIdMinus3 } /preview?published` ;
245- if ( process . env . SITE_API_MODE === 'preview' ) {
246- apiUrl = `${ instanceUrl } /services/data/v63.0/sites/${ siteIdMinus3 } /preview` ;
247- }
357+ const apiUrl = `${ instanceUrl } /services/data/${ this . config . apiVersion } /sites/${ siteIdMinus3 } /preview${ this . apiQueryParams } ` ;
248358
249359 const response = await axios . get ( apiUrl , {
250360 headers : {
0 commit comments