Conversation
501d4be to
eee043c
Compare
There was a problem hiding this comment.
Pull request overview
Adds CLI support to generate TypeScript typings for UI extension intent schemas (similar to existing tools typing) and wires the generated types into the emitted shopify.d.ts module augmentations.
Changes:
- Parse/validate intent schema JSON assets for UI extension targets and generate intent request/response/value/input/output types.
- Extend
createTypeDefinitionto optionally wrap the baseApitype withWithGeneratedIntents(and compose withWithGeneratedTools) plus supporting utility types. - Add/update Vitest coverage for intent type generation and updated
shopify.d.tsoutput expectations.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| packages/app/src/cli/models/extensions/specifications/ui_extension.ts | Collects per-entrypoint intent definitions, reads/validates schema JSON, and passes generated intent typings into createTypeDefinition. |
| packages/app/src/cli/models/extensions/specifications/ui_extension.test.ts | Updates expected shopify.d.ts output formatting and adds integration tests for intent typing generation behavior. |
| packages/app/src/cli/models/extensions/specifications/type-generation.ts | Implements intent type generation (createIntentsTypeDefinition), adds WithGeneratedIntents (and related utility types), and updates how the shopify type is constructed. |
| packages/app/src/cli/models/extensions/specifications/type-generation.test.ts | Adds unit tests for createIntentsTypeDefinition and keeps existing tools tests. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| try { | ||
| intentsTypeDefinition = await createIntentsTypeDefinition(parsedIntents) | ||
| // eslint-disable-next-line no-catch-all/no-catch-all | ||
| } catch (error) { | ||
| outputWarn( | ||
| `Failed to create intent type definition for intent schema files "${intentsDefinitions | ||
| .map((intent) => intent.schema) | ||
| .join(', ')}": ${error instanceof Error ? error.message : 'Unknown error'}`, | ||
| ) | ||
| } |
There was a problem hiding this comment.
Errors thrown by createIntentsTypeDefinition (including the AbortError raised for duplicate action/type pairs) are caught and converted into outputWarn, so the CLI won't abort on duplicates and will silently generate a shopify.d.ts without the intended intent typings. If duplicates are meant to be a hard configuration error, rethrow AbortError (or at least the duplicate-intent error) instead of warning and continuing.
| const intentSchema = await readAndValidateJsonAsset(extensionDirectory, intent.schema, IntentSchemaFileSchema) | ||
| if (intentSchema.status === 'missing') return null | ||
|
|
||
| if (intentSchema.status === 'invalid') { | ||
| outputWarn(`Invalid intent schema in "${intent.schema}": ${intentSchema.issues}`) | ||
| return null |
There was a problem hiding this comment.
When an intent schema file is missing, this code returns null without warning. The PR description (and the earlier tools handling intent) calls out that missing schema files should emit an outputWarn and skip generation; currently developers won't know why intent types disappeared.
03f0f5c to
3cbca04
Compare
1b607d9 to
674c0ab
Compare
674c0ab to
a845a47
Compare
WHY are these changes introduced?
UI extensions can now declare intents — a
declarative way of saying "this target handles the
create:application/emailintent" and shipping an input/output/value JSON Schema alongside it.
At runtime the host passes the intent payload to the extension via
shopify.intents.request, and the extension acknowledges it withshopify.intents.response.ok(data). Without type generation, developers have noway of knowing the shape of
request.data, whatrequest.valuecontains, orwhat
response.okexpects — they're back toanyterritory and have to cross-reference the schema file by hand.
We already generate types for the related
toolsconcept in the sameshopify.d.tsfile. This PR brings intents to feature parity.WHAT is this pull request doing?
For any UI-extension target that declares
[[extensions.targeting.intents]]entries with a
schemafile, the CLI now:inputSchemarequired,valueandoutputSchemaoptional).json-schema-to-typescript, yielding (for e.g.create/application/email):CreateApplicationEmailIntentInputCreateApplicationEmailIntentValueCreateApplicationEmailIntentOutputCreateApplicationEmailIntentRequest— the discriminated request shapewith literal
action/typeand a typeddata/value.ShopifyGeneratedIntentResponse<Data>— theok(data?: Data)handle.ShopifyGeneratedIntentsApi<Request, ResponseData>— request/responsepair, plus a
ShopifyGeneratedIntentVariantsunion of every declaredintent.
shopifydeclaration through anew
WithGeneratedIntents<T>wrapper that merges them with whatever thetarget's own
Api['intents']already exposes (so base host properties likecancel, etc. survive augmentation).The wrapper composes with the existing
WithGeneratedTools<T>:Duplicate
action:typepairs within a target throw anAbortError, matchingthe existing behaviour for duplicate tool names. Missing / invalid schema files
emit a warning and skip generation rather than aborting, consistent with how
tools handles bad input.
Intent types are only emitted for the extension's entry-point file, not for any
file it imports (same behaviour as tools).
Edge cases to spot-check:
schemafile: the CLI shouldoutputWarnand regenerateshopify.d.tswithout the intent types (no crash).action:typepair within a single target: the CLI shouldabort with a clear error.
valuekey: the compiled*IntentValueinterface should reflect that schema and be wired intorequest.value.