diff --git a/.changeset/fix-uid-placement-single-extension-array.md b/.changeset/fix-uid-placement-single-extension-array.md new file mode 100644 index 00000000000..889da76dfdb --- /dev/null +++ b/.changeset/fix-uid-placement-single-extension-array.md @@ -0,0 +1,5 @@ +--- +'@shopify/app': patch +--- + +Fix `uid` being written outside the `[[extensions]]` block in single-entry array-of-tables TOMLs (the shape produced by `shopify app init` templates). diff --git a/packages/app/src/cli/services/app/add-uid-to-extension-toml.test.ts b/packages/app/src/cli/services/app/add-uid-to-extension-toml.test.ts index 1406a8ce833..e3d91805dfd 100644 --- a/packages/app/src/cli/services/app/add-uid-to-extension-toml.test.ts +++ b/packages/app/src/cli/services/app/add-uid-to-extension-toml.test.ts @@ -67,6 +67,63 @@ describe('addUidToTomlsIfNecessary', () => { }) }) + test('adds uid inside the [[extensions]] block for a single-entry array TOML (matching the app init template shape)', async () => { + await inTemporaryDirectory(async (tmpDir) => { + // Given — a TOML using the modern `[[extensions]]` array-of-tables shape with a + // single extension. This is the shape produced by `shopify app init` templates. + const tomlPath = joinPath(tmpDir, 'shopify.extension.toml') + const tomlContent = `api_version = "2026-07" + +[[extensions]] +# Change the merchant-facing name of the extension in locales/en.default.json +name = "t:name" +handle = "app-home" +type = "ui_extension" + +[[extensions.targeting]] +module = "./src/AppHome.jsx" +target = "admin.app.home.render" + +[access_scopes] +scopes = "write_metaobject_definitions,write_metaobjects,write_products" +` + await writeFile(tomlPath, tomlContent) + + const extension = { + configurationPath: tomlPath, + handle: 'app-home', + isUUIDStrategyExtension: true, + uid: 'abc-123', + configuration: {}, + } as ExtensionInstance + + const client = testDeveloperPlatformClient({supportsAtomicDeployments: true}) + + // When + await addUidToTomlsIfNecessary([extension], client) + + // Then — uid must be inside the [[extensions]] block (right after handle), not at + // the top level of the file. + const updatedContent = await readFile(tomlPath) + expect(updatedContent).toBe(`api_version = "2026-07" + +[[extensions]] +# Change the merchant-facing name of the extension in locales/en.default.json +name = "t:name" +handle = "app-home" +uid = "abc-123" +type = "ui_extension" + +[[extensions.targeting]] +module = "./src/AppHome.jsx" +target = "admin.app.home.render" + +[access_scopes] +scopes = "write_metaobject_definitions,write_metaobjects,write_products" +`) + }) + }) + test('adds uid to multi-extension TOML', async () => { await inTemporaryDirectory(async (tmpDir) => { // Given diff --git a/packages/app/src/cli/services/app/add-uid-to-extension-toml.ts b/packages/app/src/cli/services/app/add-uid-to-extension-toml.ts index da816fecc0e..34b4aa17b2f 100644 --- a/packages/app/src/cli/services/app/add-uid-to-extension-toml.ts +++ b/packages/app/src/cli/services/app/add-uid-to-extension-toml.ts @@ -28,17 +28,20 @@ async function addUidToToml(extension: ExtensionInstance) { if (currentExtension && 'uid' in currentExtension) return } - if (extensionsArray && extensionsArray.length > 1) { - // Multi-extension TOML: use regex to insert uid after the correct handle. + if (extensionsArray) { + // [[extensions]] array-of-tables TOML: use regex to insert uid after the correct handle. // updateTomlValues (WASM) doesn't support patching individual array-of-tables entries, - // so transformRaw with positional insertion is the pragmatic choice here. + // so transformRaw with positional insertion is the pragmatic choice here. This applies + // whether the array has one entry or many — putting `uid` at the top level of the file + // would place it outside the [[extensions]] block, which is the wrong location. const handle = extension.handle await file.transformRaw((raw) => { const regex = new RegExp(`(\\n?(\\s*)handle\\s*=\\s*"${handle}")`) return raw.replace(regex, `$1\n$2uid = "${extension.uid}"`) }) } else { - // Single extension (or no extensions array): add uid at the top level via WASM patch + // Legacy single-extension TOML with top-level `type`/`handle` fields: add uid at the + // top level via WASM patch. await file.patch({uid: extension.uid}) } }