Skip to content

Commit 7c40a28

Browse files
Simplify code
1 parent 6d16a4a commit 7c40a28

18 files changed

Lines changed: 103 additions & 117 deletions

packages/app/src/cli/models/app/app.ts

Lines changed: 15 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -124,23 +124,19 @@ export function getAppVersionedSchema(
124124
* Get scopes from a given app.toml config file.
125125
* @param config - a configuration file
126126
*/
127-
export function getAppScopes(config: AppConfiguration): string {
128-
return (config as CurrentAppConfiguration).access_scopes?.scopes ?? ''
127+
export function getAppScopes(config: CurrentAppConfiguration): string {
128+
return config.access_scopes?.scopes ?? ''
129129
}
130130

131131
/**
132132
* Get scopes as an array from a given app.toml config file.
133133
* @param config - a configuration file
134134
*/
135-
export function getAppScopesArray(config: AppConfiguration) {
135+
export function getAppScopesArray(config: CurrentAppConfiguration) {
136136
const scopes = getAppScopes(config)
137137
return scopes.length ? scopes.split(',').map((scope) => scope.trim()) : []
138138
}
139139

140-
export function usesLegacyScopesBehavior(config: AppConfiguration) {
141-
return (config as CurrentAppConfiguration).access_scopes?.use_legacy_install_flow === true
142-
}
143-
144140
export function appHiddenConfigPath(appDirectory: string) {
145141
return joinPath(appDirectory, configurationFileNames.hiddenFolder, configurationFileNames.hiddenConfig)
146142
}
@@ -195,7 +191,7 @@ export interface Web {
195191
}
196192

197193
export interface AppConfigurationInterface<
198-
TConfig extends AppConfiguration = AppConfiguration,
194+
TConfig extends CurrentAppConfiguration = CurrentAppConfiguration,
199195
TModuleSpec extends ExtensionSpecification = ExtensionSpecification,
200196
> {
201197
directory: string
@@ -223,7 +219,7 @@ export interface ManifestModule extends JsonMapType {
223219
}
224220

225221
export interface AppInterface<
226-
TConfig extends AppConfiguration = AppConfiguration,
222+
TConfig extends CurrentAppConfiguration = CurrentAppConfiguration,
227223
TModuleSpec extends ExtensionSpecification = ExtensionSpecification,
228224
> extends AppConfigurationInterface<TConfig, TModuleSpec> {
229225
name: string
@@ -265,8 +261,8 @@ export interface AppInterface<
265261
}
266262

267263
type AppConstructor<
268-
TConfig extends AppConfiguration,
269-
TModuleSpec extends ExtensionSpecification,
264+
TConfig extends CurrentAppConfiguration = CurrentAppConfiguration,
265+
TModuleSpec extends ExtensionSpecification = ExtensionSpecification,
270266
> = AppConfigurationInterface<TConfig, TModuleSpec> & {
271267
name: string
272268
packageManager: PackageManager
@@ -283,7 +279,7 @@ type AppConstructor<
283279
}
284280

285281
export class App<
286-
TConfig extends AppConfiguration = AppConfiguration,
282+
TConfig extends CurrentAppConfiguration = CurrentAppConfiguration,
287283
TModuleSpec extends ExtensionSpecification = ExtensionSpecification,
288284
> implements AppInterface<TConfig, TModuleSpec>
289285
{
@@ -452,7 +448,7 @@ export class App<
452448
}
453449

454450
get appIsEmbedded(): boolean {
455-
return (this.configuration as CurrentAppConfiguration).embedded
451+
return this.configuration.embedded
456452
}
457453

458454
creationDefaultOptions(): CreateAppOptions {
@@ -500,20 +496,18 @@ export class App<
500496
}
501497

502498
private patchAppConfiguration(devApplicationURLs: ApplicationURLs) {
503-
const config = this.configuration as CurrentAppConfiguration
504499
this.devApplicationURLs = devApplicationURLs
505-
config.application_url = devApplicationURLs.applicationUrl
500+
this.configuration.application_url = devApplicationURLs.applicationUrl
506501
if (devApplicationURLs.appProxy) {
507-
config.app_proxy = {
502+
this.configuration.app_proxy = {
508503
url: devApplicationURLs.appProxy.proxyUrl,
509504
subpath: devApplicationURLs.appProxy.proxySubPath,
510505
prefix: devApplicationURLs.appProxy.proxySubPathPrefix,
511506
}
512507
}
513-
if (config.auth?.redirect_urls) {
514-
config.auth.redirect_urls = devApplicationURLs.redirectUrlWhitelist
508+
if (this.configuration.auth?.redirect_urls) {
509+
this.configuration.auth.redirect_urls = devApplicationURLs.redirectUrlWhitelist
515510
}
516-
this.configuration = config as TConfig
517511
}
518512

519513
/**
@@ -523,14 +517,11 @@ export class App<
523517
* @throws When app-specific webhooks are used with legacy install flow
524518
*/
525519
private validateWebhookLegacyFlowCompatibility(): void {
526-
// These fields might not exist on basic AppConfiguration but could be added by specifications
527-
const config = this.configuration as CurrentAppConfiguration
528-
529520
const hasAppSpecificWebhooks =
530-
config.webhooks?.subscriptions?.some(
521+
this.configuration.webhooks?.subscriptions?.some(
531522
(subscription: WebhookSubscription) => subscription.topics && subscription.topics.length > 0,
532523
) ?? false
533-
const usesLegacyInstallFlow = config.access_scopes?.use_legacy_install_flow === true
524+
const usesLegacyInstallFlow = this.configuration.access_scopes?.use_legacy_install_flow === true
534525

535526
if (hasAppSpecificWebhooks && usesLegacyInstallFlow) {
536527
throw new AbortError(

packages/app/src/cli/models/app/loader.test.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3480,7 +3480,7 @@ describe('getAppConfigurationState', () => {
34803480
path: expect.stringMatching(/shopify.app.toml$/),
34813481
client_id: 'abcdef',
34823482
},
3483-
isTemplateForm: false,
3483+
isLinked: true,
34843484
},
34853485
],
34863486
[
@@ -3492,7 +3492,7 @@ describe('getAppConfigurationState', () => {
34923492
client_id: 'abcdef',
34933493
something_extra: 'keep',
34943494
},
3495-
isTemplateForm: false,
3495+
isLinked: true,
34963496
},
34973497
],
34983498
[
@@ -3502,7 +3502,7 @@ describe('getAppConfigurationState', () => {
35023502
path: expect.stringMatching(/shopify.app.toml$/),
35033503
client_id: '',
35043504
},
3505-
isTemplateForm: true,
3505+
isLinked: false,
35063506
},
35073507
],
35083508
])('loads from %s', async (content, resultShouldContain) => {
@@ -3528,7 +3528,7 @@ describe('getAppConfigurationState', () => {
35283528
const result = await getAppConfigurationState(tmpDir, undefined)
35293529

35303530
expect(result.basicConfiguration.client_id).toBe('')
3531-
expect(result.isTemplateForm).toBe(true)
3531+
expect(result.isLinked).toBe(false)
35323532
})
35333533
})
35343534
})

packages/app/src/cli/models/app/loader.ts

Lines changed: 25 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ export class AppErrors {
195195
}
196196
}
197197

198-
interface AppLoaderConstructorArgs<TConfig extends AppConfiguration, TModuleSpec extends ExtensionSpecification> {
198+
interface AppLoaderConstructorArgs<TConfig extends CurrentAppConfiguration, TModuleSpec extends ExtensionSpecification> {
199199
mode?: AppLoaderMode
200200
loadedConfiguration: ConfigurationLoaderResult<TConfig, TModuleSpec>
201201
// Used when reloading an app, to avoid some expensive steps during loading.
@@ -216,7 +216,7 @@ export async function loadConfigForAppCreation(directory: string, name: string):
216216
const webs = await loadWebsForAppCreation(state.appDirectory, config.web_directories)
217217
const isLaunchable = webs.some((web) => isWebType(web, WebType.Frontend) || isWebType(web, WebType.Backend))
218218

219-
const scopesArray = getAppScopesArray(config)
219+
const scopesArray = getAppScopesArray(config as CurrentAppConfiguration)
220220

221221
return {
222222
isLaunchable,
@@ -259,19 +259,19 @@ async function loadSingleWeb(webConfigPath: string, abortOrReport: AbortOrReport
259259
* If the App contains extensions not supported by the current specs and mode is strict, it will throw an error.
260260
*/
261261
export async function loadApp<TModuleSpec extends ExtensionSpecification = ExtensionSpecification>(
262-
options: Omit<AppLoaderConstructorArgs<AppConfiguration, ExtensionSpecification>, 'loadedConfiguration'> & {
262+
options: Omit<AppLoaderConstructorArgs<CurrentAppConfiguration, ExtensionSpecification>, 'loadedConfiguration'> & {
263263
directory: string
264264
userProvidedConfigName: string | undefined
265265
specifications: TModuleSpec[]
266266
remoteFlags?: Flag[]
267267
},
268-
): Promise<AppInterface<AppConfiguration, TModuleSpec>> {
268+
): Promise<AppInterface<CurrentAppConfiguration, TModuleSpec>> {
269269
const specifications = options.specifications
270270

271271
const state = await getAppConfigurationState(options.directory, options.userProvidedConfigName)
272272
const loadedConfiguration = await loadAppConfigurationFromState(state, specifications, options.remoteFlags ?? [])
273273

274-
const loader = new AppLoader<AppConfiguration, TModuleSpec>({
274+
const loader = new AppLoader<CurrentAppConfiguration, TModuleSpec>({
275275
mode: options.mode,
276276
loadedConfiguration,
277277
})
@@ -288,7 +288,7 @@ export type OpaqueAppLoadResult =
288288
| {
289289
state: 'loaded-app'
290290
app: AppInterface
291-
configuration: AppConfiguration
291+
configuration: CurrentAppConfiguration
292292
}
293293
| {
294294
state: 'loaded-template'
@@ -374,8 +374,8 @@ export async function reloadApp(app: AppLinkedInterface): Promise<AppLinkedInter
374374
return loader.loaded()
375375
}
376376

377-
export async function loadAppUsingConfigurationState<TConfig extends AppConfigurationState>(
378-
configState: TConfig,
377+
export async function loadAppUsingConfigurationState(
378+
configState: AppConfigurationState,
379379
{
380380
specifications,
381381
remoteFlags,
@@ -385,7 +385,7 @@ export async function loadAppUsingConfigurationState<TConfig extends AppConfigur
385385
remoteFlags?: Flag[]
386386
mode: AppLoaderMode
387387
},
388-
): Promise<AppInterface<LoadedAppConfigFromConfigState<typeof configState>, RemoteAwareExtensionSpecification>> {
388+
): Promise<AppInterface<CurrentAppConfiguration, RemoteAwareExtensionSpecification>> {
389389
const loadedConfiguration = await loadAppConfigurationFromState(configState, specifications, remoteFlags ?? [])
390390

391391
const loader = new AppLoader({
@@ -395,12 +395,7 @@ export async function loadAppUsingConfigurationState<TConfig extends AppConfigur
395395
return loader.loaded()
396396
}
397397

398-
/**
399-
* Given basic information about an app's configuration state, what should the validated configuration type be?
400-
*/
401-
type LoadedAppConfigFromConfigState<TConfigState> = TConfigState extends AppConfigurationStateLinked
402-
? CurrentAppConfiguration
403-
: never
398+
type LoadedAppConfigFromConfigState = CurrentAppConfiguration
404399

405400
export function getDotEnvFileName(configurationPath: string) {
406401
const configurationShorthand: string | undefined = getAppConfigurationShorthand(configurationPath)
@@ -416,7 +411,7 @@ export async function loadDotEnv(appDirectory: string, configurationPath: string
416411
return dotEnvFile
417412
}
418413

419-
class AppLoader<TConfig extends AppConfiguration, TModuleSpec extends ExtensionSpecification> {
414+
class AppLoader<TConfig extends CurrentAppConfiguration, TModuleSpec extends ExtensionSpecification> {
420415
private readonly mode: AppLoaderMode
421416
private readonly errors: AppErrors = new AppErrors()
422417
private readonly specifications: TModuleSpec[]
@@ -445,8 +440,8 @@ class AppLoader<TConfig extends AppConfiguration, TModuleSpec extends ExtensionS
445440

446441
// These don't need to be processed again if the app is being reloaded
447442
// name is required by BrandingSchema, so it must be present in the configuration
448-
const configName = (configuration as CurrentAppConfiguration).name
449-
const configHandle: string | undefined = (configuration as CurrentAppConfiguration).handle
443+
const configName = configuration.name
444+
const configHandle: string | undefined = configuration.handle
450445
const name: string = this.previousApp?.name ?? configHandle ?? configName ?? ''
451446
const nodeDependencies = this.previousApp?.nodeDependencies ?? (await getDependencies(packageJSONPath))
452447
const packageManager = this.previousApp?.packageManager ?? (await getPackageManager(directory))
@@ -836,7 +831,7 @@ class AppLoader<TConfig extends AppConfiguration, TModuleSpec extends ExtensionS
836831
return generateApplicationURLs(
837832
previousDevUrls.applicationUrl,
838833
webs.map(({configuration}) => configuration.auth_callback_path).find((path) => path),
839-
(currentConfiguration as CurrentAppConfiguration).app_proxy,
834+
currentConfiguration.app_proxy,
840835
)
841836
}
842837
}
@@ -884,7 +879,7 @@ type ConfigurationLoadResultMetadata = {
884879
)
885880

886881
type ConfigurationLoaderResult<
887-
TConfig extends AppConfiguration,
882+
TConfig extends CurrentAppConfiguration,
888883
TModuleSpec extends ExtensionSpecification,
889884
> = AppConfigurationInterface<TConfig, TModuleSpec> & {
890885
configurationLoadResultMetadata: ConfigurationLoadResultMetadata
@@ -897,13 +892,11 @@ interface AppConfigurationStateBasics {
897892
configurationFileName: AppConfigurationFileName
898893
}
899894

900-
export type AppConfigurationStateLinked = AppConfigurationStateBasics & {
895+
export type AppConfigurationState = AppConfigurationStateBasics & {
901896
basicConfiguration: BasicAppConfigurationWithoutModules
902-
isTemplateForm: boolean
897+
isLinked: boolean
903898
}
904899

905-
type AppConfigurationState = AppConfigurationStateLinked
906-
907900
/**
908901
* Get the app configuration state from the file system.
909902
*
@@ -942,8 +935,7 @@ export async function getAppConfigurationState(
942935

943936
const parsedConfig = await parseConfigurationFile(AppSchema, configurationPath)
944937

945-
// Check if the config is in template form by verifying if client_id is empty
946-
const isTemplateForm = parsedConfig.client_id === ''
938+
const isLinked = parsedConfig.client_id !== ''
947939

948940
return {
949941
appDirectory,
@@ -954,7 +946,7 @@ export async function getAppConfigurationState(
954946
},
955947
configSource,
956948
configurationFileName,
957-
isTemplateForm,
949+
isLinked,
958950
}
959951
}
960952

@@ -963,28 +955,25 @@ export async function getAppConfigurationState(
963955
*
964956
* This is typically called after getting remote-aware extension specifications. The app configuration is validated acordingly.
965957
*/
966-
async function loadAppConfigurationFromState<
967-
TConfig extends AppConfigurationState,
968-
TModuleSpec extends ExtensionSpecification,
969-
>(
970-
configState: TConfig,
958+
async function loadAppConfigurationFromState<TModuleSpec extends ExtensionSpecification>(
959+
configState: AppConfigurationState,
971960
specifications: TModuleSpec[],
972961
remoteFlags: Flag[],
973-
): Promise<ConfigurationLoaderResult<LoadedAppConfigFromConfigState<TConfig>, TModuleSpec>> {
962+
): Promise<ConfigurationLoaderResult<LoadedAppConfigFromConfigState, TModuleSpec>> {
974963
const file: JsonMapType = {
975964
...configState.basicConfiguration,
976965
} as JsonMapType
977966
delete file.path
978967
const appVersionedSchema = getAppVersionedSchema(specifications)
979-
const schemaForConfigurationFile = appVersionedSchema as SchemaForConfig<LoadedAppConfigFromConfigState<TConfig>>
968+
const schemaForConfigurationFile = appVersionedSchema as SchemaForConfig<LoadedAppConfigFromConfigState>
980969

981970
const configuration = (await parseConfigurationFile(
982971
schemaForConfigurationFile,
983972
configState.configurationPath,
984973
abort,
985974
decodeToml,
986975
file,
987-
)) as LoadedAppConfigFromConfigState<TConfig>
976+
)) as LoadedAppConfigFromConfigState
988977
const allClientIdsByConfigName = await getAllLinkedConfigClientIds(configState.appDirectory, {
989978
[configState.configurationFileName]: configuration.client_id,
990979
})
@@ -994,7 +983,6 @@ async function loadAppConfigurationFromState<
994983
allClientIdsByConfigName,
995984
}
996985

997-
// enhance metadata based on the config type
998986
let gitTracked = false
999987
try {
1000988
gitTracked = await checkIfGitTracked(configState.appDirectory, configState.configurationPath)
@@ -1009,8 +997,7 @@ async function loadAppConfigurationFromState<
1009997
name: configState.configurationFileName,
1010998
gitTracked,
1011999
source: configState.configSource,
1012-
usesCliManagedUrls: (configuration as LoadedAppConfigFromConfigState<AppConfigurationStateLinked>).build
1013-
?.automatically_update_urls_on_dev,
1000+
usesCliManagedUrls: configuration.build?.automatically_update_urls_on_dev,
10141001
}
10151002

10161003
return {

packages/app/src/cli/services/app-context.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ client_id="test-api-key"`
158158
configurationPath: `${tmp}/shopify.app.toml`,
159159
configSource: 'cached',
160160
configurationFileName: 'shopify.app.toml',
161-
isTemplateForm: false,
161+
isLinked: true,
162162
basicConfiguration: {
163163
client_id: 'test-api-key',
164164
path: normalizePath(joinPath(tmp, 'shopify.app.toml')),

packages/app/src/cli/services/app-context.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,10 +72,9 @@ export async function linkedAppContext({
7272
let configState = await getAppConfigurationState(directory, userProvidedConfigName)
7373
let remoteApp: OrganizationApp | undefined
7474

75-
// If forceRelink is true, force a link.
76-
if (forceRelink) {
77-
// If forceRelink is true, we don't want to use the cached config name and instead prompt the user for a new one.
78-
const result = await link({directory, apiKey: clientId, configName: undefined})
75+
if (!configState.isLinked || forceRelink) {
76+
const configName = forceRelink ? undefined : configState.configurationFileName
77+
const result = await link({directory, apiKey: clientId, configName})
7978
remoteApp = result.remoteApp
8079
configState = result.state
8180
}

0 commit comments

Comments
 (0)