Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions packages/app/src/cli/models/app/app.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -175,16 +175,16 @@ describe('getUIExtensionRendererVersion', () => {
})

describe('getAppScopes', () => {
test('returns the access_scopes.scopes key', () => {
test('returns the access_scopes.scopes key with normalization', () => {
const config = {...DEFAULT_CONFIG, access_scopes: {scopes: 'read_themes,read_themes'}}
expect(getAppScopes(config)).toEqual('read_themes,read_themes')
expect(getAppScopes(config)).toEqual('read_themes')
})
})

describe('getAppScopesArray', () => {
test('returns the access_scopes.scopes key', () => {
test('returns the access_scopes.scopes key as array with normalization', () => {
const config = {...DEFAULT_CONFIG, access_scopes: {scopes: 'read_themes, read_order ,write_products'}}
expect(getAppScopesArray(config)).toEqual(['read_themes', 'read_order', 'write_products'])
expect(getAppScopesArray(config)).toEqual(['read_order', 'read_themes', 'write_products'])
})
})

Expand Down
28 changes: 27 additions & 1 deletion packages/app/src/cli/models/app/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {configurationFileNames} from '../../constants.js'
import {ApplicationURLs} from '../../services/dev/urls.js'
import {patchAppHiddenConfigFile} from '../../services/app/patch-app-configuration-file.js'
import {WebhookSubscription} from '../extensions/specifications/types/app_config_webhook.js'
import {normalizeDelimitedString} from '@shopify/cli-kit/common/string'
import {joinPath} from '@shopify/cli-kit/node/path'
import {ZodObjectOf, zod} from '@shopify/cli-kit/node/schema'
import {DotEnvFile} from '@shopify/cli-kit/node/dot-env'
Expand Down Expand Up @@ -72,6 +73,31 @@ export const AppSchema = zod
})
.passthrough()

/**
* Schema for loading template config during app init.
* Uses passthrough() to allow any extra keys from full-featured templates
* (e.g., metafields, metaobjects, webhooks) without strict validation.
*/
export const TemplateConfigSchema = zod
.object({
scopes: zod.string().optional(),
access_scopes: zod
.object({
scopes: zod.string(),
})
.optional(),
web_directories: zod.array(zod.string()).optional(),
})
.passthrough()

export type TemplateConfig = zod.infer<typeof TemplateConfigSchema>

export function getTemplateScopesArray(config: TemplateConfig): string[] {
const scopesString = normalizeDelimitedString(config.scopes ?? config.access_scopes?.scopes)
if (!scopesString || scopesString.length === 0) return []
return scopesString.split(',').map((scope) => scope.trim())
}

/**
* Hidden configuration for an app. Stored inside ./shopify/project.json
* This is a set of values that are needed by the CLI that are not part of the app configuration.
Expand Down Expand Up @@ -127,7 +153,7 @@ export function getAppVersionedSchema(
* @param config - a configuration file
*/
export function getAppScopes(config: CurrentAppConfiguration): string {
return config.access_scopes?.scopes ?? ''
return normalizeDelimitedString(config.access_scopes?.scopes) ?? ''
}

/**
Expand Down
13 changes: 13 additions & 0 deletions packages/app/src/cli/models/app/loader.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3486,6 +3486,19 @@ describe('WebhooksSchema', () => {

describe('getAppConfigurationState', () => {
test.each([
[
`scopes = " write_xyz, write_abc "`,
{
state: 'template-only',
configSource: 'cached',
configurationFileName: 'shopify.app.toml',
appDirectory: expect.any(String),
configurationPath: expect.stringMatching(/shopify.app.toml$/),
startingOptions: {
scopes: ' write_xyz, write_abc ',
},
},
],
[
`client_id="abcdef"`,
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import {validateUrl} from '../../app/validation/common.js'
import {TransformationConfig, createConfigExtensionSpecification} from '../specification.js'
import {BaseSchemaWithoutHandle} from '../schemas.js'
import {normalizeDelimitedString} from '@shopify/cli-kit/common/string'
import {zod} from '@shopify/cli-kit/node/schema'

const AppAccessSchema = BaseSchemaWithoutHandle.extend({
Expand All @@ -17,10 +16,7 @@ const AppAccessSchema = BaseSchemaWithoutHandle.extend({
.optional(),
access_scopes: zod
.object({
scopes: zod
.string()
.transform((scopes) => normalizeDelimitedString(scopes) ?? '')
.optional(),
scopes: zod.string().optional(),
required_scopes: zod.array(zod.string()).optional(),
optional_scopes: zod.array(zod.string()).optional(),
use_legacy_install_flow: zod.boolean().optional(),
Expand Down
Loading