Skip to content

Commit d01a506

Browse files
committed
Add support for registering app intents
1 parent 3e48836 commit d01a506

File tree

8 files changed

+717
-19
lines changed

8 files changed

+717
-19
lines changed

packages/app/src/cli/models/extensions/extension-instance.test.ts

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,77 @@ describe('build', async () => {
192192
})
193193
})
194194

195+
test('copies intent schema files when building UI extensions with intents', async () => {
196+
await inTemporaryDirectory(async (tmpDir) => {
197+
// Given
198+
const intentsDir = joinPath(tmpDir, 'intents')
199+
await mkdir(intentsDir)
200+
await writeFile(joinPath(intentsDir, 'create-schema.json'), '{"type": "create"}')
201+
await writeFile(joinPath(intentsDir, 'update-schema.json'), '{"type": "update"}')
202+
203+
const distDir = joinPath(tmpDir, 'dist')
204+
await mkdir(distDir)
205+
206+
const extensionInstance = await testUIExtension({
207+
type: 'ui_extension',
208+
directory: tmpDir,
209+
configuration: {
210+
name: 'test-ui-extension',
211+
type: 'ui_extension',
212+
api_version: '2025-10',
213+
metafields: [],
214+
capabilities: {
215+
network_access: false,
216+
api_access: false,
217+
block_progress: false,
218+
},
219+
extension_points: [
220+
{
221+
target: 'EXTENSION::POINT::A',
222+
module: './src/ExtensionPointA.js',
223+
build_manifest: {
224+
assets: {
225+
main: {
226+
filepath: 'test-ui-extension.js',
227+
module: './src/ExtensionPointA.js',
228+
},
229+
intents: [
230+
{
231+
filepath: 'test-ui-extension-intent-create-app_intent-create-schema.json',
232+
module: './intents/create-schema.json',
233+
static: true,
234+
},
235+
{
236+
filepath: 'test-ui-extension-intent-update-app_intent-update-schema.json',
237+
module: './intents/update-schema.json',
238+
static: true,
239+
},
240+
],
241+
},
242+
},
243+
},
244+
],
245+
},
246+
outputPath: joinPath(distDir, 'test-ui-extension.js'),
247+
})
248+
249+
// When
250+
await extensionInstance.copyStaticAssets()
251+
252+
// Then
253+
const createSchemaOutput = joinPath(distDir, 'test-ui-extension-intent-create-app_intent-create-schema.json')
254+
const updateSchemaOutput = joinPath(distDir, 'test-ui-extension-intent-update-app_intent-update-schema.json')
255+
256+
expect(fileExistsSync(createSchemaOutput)).toBe(true)
257+
expect(fileExistsSync(updateSchemaOutput)).toBe(true)
258+
259+
const createContent = await readFile(createSchemaOutput)
260+
const updateContent = await readFile(updateSchemaOutput)
261+
expect(createContent).toBe('{"type": "create"}')
262+
expect(updateContent).toBe('{"type": "update"}')
263+
})
264+
})
265+
195266
test('does not copy shopify.extension.toml file when bundling theme extensions', async () => {
196267
await inTemporaryDirectory(async (tmpDir) => {
197268
// Given

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,17 @@ const NewExtensionPointSchema = zod.object({
4747
should_render: ShouldRenderSchema.optional(),
4848
tools: zod.string().optional(),
4949
instructions: zod.string().optional(),
50+
intents: zod
51+
.array(
52+
zod.object({
53+
type: zod.string(),
54+
action: zod.string(),
55+
schema: zod.string(),
56+
name: zod.string().optional(),
57+
description: zod.string().optional(),
58+
}),
59+
)
60+
.optional(),
5061
metafields: zod.array(MetafieldSchema).optional(),
5162
default_placement: zod.string().optional(),
5263
urls: zod

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ export enum AssetIdentifier {
4040
Main = 'main',
4141
Tools = 'tools',
4242
Instructions = 'instructions',
43+
Intents = 'intents',
4344
}
4445

4546
export interface Asset {

0 commit comments

Comments
 (0)