@@ -11,10 +11,11 @@ import {UIExtensionSchema} from '../extensions/specifications/ui_extension.js'
1111import { Flag } from '../../utilities/developer-platform-client.js'
1212import { AppAccessSpecIdentifier } from '../extensions/specifications/app_config_app_access.js'
1313import { WebhookSubscriptionSchema } from '../extensions/specifications/app_config_webhook_schemas/webhook_subscription_schema.js'
14+ import { configurationFileNames } from '../../constants.js'
1415import { ZodObjectOf , zod } from '@shopify/cli-kit/node/schema'
1516import { DotEnvFile } from '@shopify/cli-kit/node/dot-env'
1617import { getDependencies , PackageManager , readAndParsePackageJson } from '@shopify/cli-kit/node/node-package-manager'
17- import { fileRealPath , findPathUp } from '@shopify/cli-kit/node/fs'
18+ import { fileRealPath , findPathUp , writeFile } from '@shopify/cli-kit/node/fs'
1819import { joinPath } from '@shopify/cli-kit/node/path'
1920import { AbortError } from '@shopify/cli-kit/node/error'
2021import { normalizeDelimitedString } from '@shopify/cli-kit/common/string'
@@ -80,6 +81,15 @@ export const AppSchema = zod.object({
8081 web_directories : zod . array ( zod . string ( ) ) . optional ( ) ,
8182} )
8283
84+ /**
85+ * Hidden configuration for an app. Stored inside ./shopify/project.json
86+ * This is a set of values that are needed by the CLI that are not part of the app configuration.
87+ * These are not meant to be git tracked and the user doesn't need to know about their existence.
88+ */
89+ export interface AppHiddenConfig {
90+ dev_store_url ?: string
91+ }
92+
8393/**
8494 * Utility schema that matches freshly minted or normal, linked, apps.
8595 */
@@ -179,6 +189,10 @@ export function usesLegacyScopesBehavior(config: AppConfiguration) {
179189 return false
180190}
181191
192+ export function appHiddenConfigPath ( appDirectory : string ) {
193+ return joinPath ( appDirectory , configurationFileNames . hiddenFolder , configurationFileNames . hiddenConfig )
194+ }
195+
182196/**
183197 * Get the field names from the configuration that aren't found in the basic built-in app configuration schema.
184198 */
@@ -256,6 +270,7 @@ export interface AppInterface<
256270 realExtensions : ExtensionInstance [ ]
257271 draftableExtensions : ExtensionInstance [ ]
258272 errors ?: AppErrors
273+ hiddenConfig : AppHiddenConfig
259274 includeConfigOnDeploy : boolean | undefined
260275 updateDependencies : ( ) => Promise < void >
261276 extensionsForType : ( spec : { identifier : string ; externalIdentifier : string } ) => ExtensionInstance [ ]
@@ -274,6 +289,7 @@ export interface AppInterface<
274289 creationDefaultOptions ( ) : AppCreationDefaultOptions
275290 manifest : ( ) => Promise < JsonMapType >
276291 removeExtension : ( extensionUid : string ) => void
292+ updateHiddenConfig : ( values : Partial < AppHiddenConfig > ) => Promise < void >
277293}
278294
279295type AppConstructor <
@@ -290,6 +306,7 @@ type AppConstructor<
290306 errors ?: AppErrors
291307 specifications : ExtensionSpecification [ ]
292308 remoteFlags ?: Flag [ ]
309+ hiddenConfig : AppHiddenConfig
293310}
294311
295312export class App <
@@ -311,6 +328,7 @@ export class App<
311328 configSchema : ZodObjectOf < Omit < TConfig , 'path' > >
312329 remoteFlags : Flag [ ]
313330 realExtensions : ExtensionInstance [ ]
331+ hiddenConfig : AppHiddenConfig
314332
315333 constructor ( {
316334 name,
@@ -326,6 +344,7 @@ export class App<
326344 specifications,
327345 configSchema,
328346 remoteFlags,
347+ hiddenConfig,
329348 } : AppConstructor < TConfig , TModuleSpec > ) {
330349 this . name = name
331350 this . directory = directory
@@ -340,6 +359,7 @@ export class App<
340359 this . specifications = specifications
341360 this . configSchema = configSchema ?? AppSchema
342361 this . remoteFlags = remoteFlags ?? [ ]
362+ this . hiddenConfig = hiddenConfig
343363 }
344364
345365 get allExtensions ( ) {
@@ -388,6 +408,11 @@ export class App<
388408 this . nodeDependencies = nodeDependencies
389409 }
390410
411+ async updateHiddenConfig ( values : Partial < AppHiddenConfig > ) {
412+ this . hiddenConfig = { ...this . hiddenConfig , ...values }
413+ await writeFile ( appHiddenConfigPath ( this . directory ) , JSON . stringify ( this . hiddenConfig , null , 2 ) )
414+ }
415+
391416 async preDeployValidation ( ) {
392417 const functionExtensionsWithUiHandle = this . allExtensions . filter (
393418 ( ext ) => ext . isFunctionExtension && ( ext . configuration as unknown as FunctionConfigType ) . ui ?. handle ,
0 commit comments