Skip to content

Commit e4026e9

Browse files
marcelobarretocodex
andcommitted
Add Customer Account EXAF address types
Expose structured extended address fields and address codes on the Customer Account mailing address API so public extension types and reference docs match the runtime data provided by Customer Account Web. Co-authored-by: GPT-5.5 <noreply@openai.com> Orchestrated-by: ae <noreply@shopify.com>
1 parent 9a1b5d4 commit e4026e9

5 files changed

Lines changed: 292 additions & 3 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@shopify/ui-extensions': minor
3+
---
4+
5+
Add structured extended address fields to Customer Account order address APIs.

packages/ui-extensions/docs/surfaces/customer-account/build-docs.mjs

Lines changed: 89 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,90 @@ const cleanupTempFiles = async (tempFiles) => {
6868
);
6969
};
7070

71+
const customerAccountMailingAddressFields = [
72+
{
73+
filePath: 'src/surfaces/customer-account/api/shared.ts',
74+
syntaxKind: 'PropertySignature',
75+
name: 'extendedFields',
76+
value: 'AddressExtendedFields',
77+
description:
78+
'Structured address components for countries and regions that collect them. Values are `null` when the address only has flat address lines.',
79+
isOptional: true,
80+
},
81+
{
82+
filePath: 'src/surfaces/customer-account/api/shared.ts',
83+
syntaxKind: 'PropertySignature',
84+
name: 'addressCode',
85+
value: 'string | null',
86+
description:
87+
'A country-specific address code, such as a short code or postal delivery code.',
88+
isOptional: true,
89+
examples: [
90+
{
91+
title: 'Example',
92+
description: '',
93+
tabs: [{code: "'01001-000'", title: 'Example'}],
94+
},
95+
],
96+
},
97+
];
98+
99+
const customerAccountMailingAddressValue = ` /**
100+
* Structured address components for countries and regions that collect them.
101+
* Values are \`null\` when the address only has flat address lines.
102+
*/
103+
extendedFields?: AddressExtendedFields;
104+
105+
/**
106+
* A country-specific address code, such as a short code or postal delivery code.
107+
*
108+
* @example '01001-000'
109+
*/
110+
addressCode?: string | null;
111+
112+
`;
113+
114+
const addCustomerAccountMailingAddressDocs = async (generatedDocsV2Path) => {
115+
const content = await fs.readFile(generatedDocsV2Path, 'utf8');
116+
const generatedDocs = JSON.parse(content);
117+
const mailingAddressDocs = generatedDocs.MailingAddress;
118+
119+
if (!mailingAddressDocs) return;
120+
121+
const [sourcePath] = Object.keys(mailingAddressDocs);
122+
const docs = mailingAddressDocs[sourcePath];
123+
124+
if (!docs?.members || !docs?.value) return;
125+
126+
const existingMemberNames = new Set(
127+
docs.members.map((member) => member.name),
128+
);
129+
130+
const missingFields = customerAccountMailingAddressFields.filter(
131+
(field) => !existingMemberNames.has(field.name),
132+
);
133+
134+
if (missingFields.length > 0) {
135+
const address2Index = docs.members.findIndex(
136+
(member) => member.name === 'address2',
137+
);
138+
const insertIndex = address2Index === -1 ? docs.members.length : address2Index + 1;
139+
docs.members.splice(insertIndex, 0, ...missingFields);
140+
}
141+
142+
if (!docs.value.includes('extendedFields?: AddressExtendedFields;')) {
143+
docs.value = docs.value.replace(
144+
' /**\n * The city, town, or village of the address.',
145+
`${customerAccountMailingAddressValue} /**\n * The city, town, or village of the address.`,
146+
);
147+
}
148+
149+
await fs.writeFile(
150+
generatedDocsV2Path,
151+
`${JSON.stringify(generatedDocs, null, 2)}\n`,
152+
);
153+
};
154+
71155
const generateExtensionsDocs = async () => {
72156
console.log(
73157
`Building Customer Account UI Extensions docs for ${EXTENSIONS_API_VERSION} version`,
@@ -98,12 +182,16 @@ const generateExtensionsDocs = async () => {
98182
replaceValue: '',
99183
});
100184

185+
const generatedDocsV2Path = path.join(outputDir, generatedDocsDataV2File);
186+
101187
// Replace 'unstable' with the exact API version in relative doc links
102188
await replaceFileContent({
103-
filePaths: path.join(outputDir, generatedDocsDataV2File),
189+
filePaths: generatedDocsV2Path,
104190
searchValue: '/docs/api//unstable/',
105191
replaceValue: `/docs/api/customer-account-ui-extensions/${EXTENSIONS_API_VERSION}`,
106192
});
193+
194+
await addCustomerAccountMailingAddressDocs(generatedDocsV2Path);
107195
};
108196

109197
let checkoutTempFiles = [];

packages/ui-extensions/docs/surfaces/customer-account/generated/customer_account_ui_extensions/2026-07-rc/generated_docs_data_v2.json

Lines changed: 141 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,34 @@
171171
}
172172
]
173173
},
174+
{
175+
"filePath": "src/surfaces/customer-account/api/shared.ts",
176+
"syntaxKind": "PropertySignature",
177+
"name": "extendedFields",
178+
"value": "AddressExtendedFields",
179+
"description": "Structured address components for countries and regions that collect them. Values are `null` when the address only has flat address lines.",
180+
"isOptional": true
181+
},
182+
{
183+
"filePath": "src/surfaces/customer-account/api/shared.ts",
184+
"syntaxKind": "PropertySignature",
185+
"name": "addressCode",
186+
"value": "string | null",
187+
"description": "A country-specific address code, such as a short code or postal delivery code.",
188+
"isOptional": true,
189+
"examples": [
190+
{
191+
"title": "Example",
192+
"description": "",
193+
"tabs": [
194+
{
195+
"code": "'01001-000'",
196+
"title": "Example"
197+
}
198+
]
199+
}
200+
]
201+
},
174202
{
175203
"filePath": "src/surfaces/checkout/api/shared.ts",
176204
"syntaxKind": "PropertySignature",
@@ -352,7 +380,7 @@
352380
]
353381
}
354382
],
355-
"value": "export interface MailingAddress {\n /**\n * The buyer's full name, typically a combination of first and last name.\n * The value is `undefined` if the buyer didn't provide a name.\n *\n * {% include /apps/checkout/privacy-icon.md %} Requires level 2 access to [protected customer data](/docs/apps/store/data-protection/protected-customer-data).\n *\n * @example 'John Doe'\n */\n name?: string;\n\n /**\n * The buyer's first name. Use this alongside `lastName` when you need to\n * display or process name parts separately. The value is `undefined` if\n * the buyer didn't provide a first name or the store doesn't collect\n * split names.\n *\n * {% include /apps/checkout/privacy-icon.md %} Requires level 2 access to [protected customer data](/docs/apps/store/data-protection/protected-customer-data).\n *\n * @example 'John'\n */\n firstName?: string;\n\n /**\n * The buyer's last name. Use this alongside `firstName` when you need to\n * display or process name parts separately. The value is `undefined` if\n * the buyer didn't provide a last name or the store doesn't collect\n * split names.\n *\n * {% include /apps/checkout/privacy-icon.md %} Requires level 2 access to [protected customer data](/docs/apps/store/data-protection/protected-customer-data).\n *\n * @example 'Doe'\n */\n lastName?: string;\n\n /**\n * The buyer's company name. The value is `undefined` if the buyer didn't\n * enter a company or the store doesn't collect company names.\n *\n * {% include /apps/checkout/privacy-icon.md %} Requires level 1 access to [protected customer data](/docs/apps/store/data-protection/protected-customer-data).\n *\n * @example 'Shopify'\n */\n company?: string;\n\n /**\n * The first line of the street address, including the street number and\n * name. The value is `undefined` if the buyer hasn't entered an address yet.\n *\n * {% include /apps/checkout/privacy-icon.md %} Requires level 2 access to [protected customer data](/docs/apps/store/data-protection/protected-customer-data).\n *\n * @example '151 O'Connor Street'\n */\n address1?: string;\n\n /**\n * The second line of the buyer's address, such as apartment number, suite,\n * or unit. The value is `undefined` if the buyer didn't provide a second\n * address line.\n *\n * {% include /apps/checkout/privacy-icon.md %} Requires level 2 access to [protected customer data](/docs/apps/store/data-protection/protected-customer-data).\n *\n * @example 'Ground floor'\n */\n address2?: string;\n\n /**\n * The city, town, or village of the address. The value is `undefined` if\n * the buyer hasn't entered a city yet.\n *\n * {% include /apps/checkout/privacy-icon.md %} Requires level 2 access to [protected customer data](/docs/apps/store/data-protection/protected-customer-data).\n *\n * @example 'Ottawa'\n */\n city?: string;\n\n /**\n * The postal code or ZIP code of the address, used for mail sorting and\n * delivery routing. The value is `undefined` if the buyer hasn't entered\n * one yet or the country doesn't use postal codes.\n *\n * {% include /apps/checkout/privacy-icon.md %} Requires level 2 access to [protected customer data](/docs/apps/store/data-protection/protected-customer-data).\n *\n * @example 'K2P 2L8'\n */\n zip?: string;\n\n /**\n * The two-letter country code in [ISO 3166 Alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2)\n * format. The value is `undefined` if the buyer hasn't selected a country\n * yet.\n *\n * {% include /apps/checkout/privacy-icon.md %} Requires level 2 access to [protected customer data](/docs/apps/store/data-protection/protected-customer-data).\n *\n * @example 'CA' for Canada.\n */\n countryCode?: CountryCode;\n\n /**\n * The province, state, prefecture, or region code of the address. The\n * format varies by country. The value is `undefined` if the buyer hasn't\n * selected one yet or the country doesn't have provinces.\n *\n * {% include /apps/checkout/privacy-icon.md %} Requires level 2 access to [protected customer data](/docs/apps/store/data-protection/protected-customer-data).\n *\n * @example 'ON' for Ontario.\n */\n provinceCode?: string;\n\n /**\n * The phone number associated with the address, typically in international\n * format. The value is `undefined` if the buyer didn't provide a phone\n * number or the store doesn't collect phone numbers.\n *\n * {% include /apps/checkout/privacy-icon.md %} Requires level 2 access to [protected customer data](/docs/apps/store/data-protection/protected-customer-data).\n *\n * @example '+1 613 111 2222'\n */\n phone?: string;\n}"
383+
"value": "export interface MailingAddress {\n /**\n * The buyer's full name, typically a combination of first and last name.\n * The value is `undefined` if the buyer didn't provide a name.\n *\n * {% include /apps/checkout/privacy-icon.md %} Requires level 2 access to [protected customer data](/docs/apps/store/data-protection/protected-customer-data).\n *\n * @example 'John Doe'\n */\n name?: string;\n\n /**\n * The buyer's first name. Use this alongside `lastName` when you need to\n * display or process name parts separately. The value is `undefined` if\n * the buyer didn't provide a first name or the store doesn't collect\n * split names.\n *\n * {% include /apps/checkout/privacy-icon.md %} Requires level 2 access to [protected customer data](/docs/apps/store/data-protection/protected-customer-data).\n *\n * @example 'John'\n */\n firstName?: string;\n\n /**\n * The buyer's last name. Use this alongside `firstName` when you need to\n * display or process name parts separately. The value is `undefined` if\n * the buyer didn't provide a last name or the store doesn't collect\n * split names.\n *\n * {% include /apps/checkout/privacy-icon.md %} Requires level 2 access to [protected customer data](/docs/apps/store/data-protection/protected-customer-data).\n *\n * @example 'Doe'\n */\n lastName?: string;\n\n /**\n * The buyer's company name. The value is `undefined` if the buyer didn't\n * enter a company or the store doesn't collect company names.\n *\n * {% include /apps/checkout/privacy-icon.md %} Requires level 1 access to [protected customer data](/docs/apps/store/data-protection/protected-customer-data).\n *\n * @example 'Shopify'\n */\n company?: string;\n\n /**\n * The first line of the street address, including the street number and\n * name. The value is `undefined` if the buyer hasn't entered an address yet.\n *\n * {% include /apps/checkout/privacy-icon.md %} Requires level 2 access to [protected customer data](/docs/apps/store/data-protection/protected-customer-data).\n *\n * @example '151 O'Connor Street'\n */\n address1?: string;\n\n /**\n * The second line of the buyer's address, such as apartment number, suite,\n * or unit. The value is `undefined` if the buyer didn't provide a second\n * address line.\n *\n * {% include /apps/checkout/privacy-icon.md %} Requires level 2 access to [protected customer data](/docs/apps/store/data-protection/protected-customer-data).\n *\n * @example 'Ground floor'\n */\n address2?: string;\n\n /**\n * Structured address components for countries and regions that collect them.\n * Values are `null` when the address only has flat address lines.\n */\n extendedFields?: AddressExtendedFields;\n\n /**\n * A country-specific address code, such as a short code or postal delivery code.\n *\n * @example '01001-000'\n */\n addressCode?: string | null;\n\n /**\n * The city, town, or village of the address. The value is `undefined` if\n * the buyer hasn't entered a city yet.\n *\n * {% include /apps/checkout/privacy-icon.md %} Requires level 2 access to [protected customer data](/docs/apps/store/data-protection/protected-customer-data).\n *\n * @example 'Ottawa'\n */\n city?: string;\n\n /**\n * The postal code or ZIP code of the address, used for mail sorting and\n * delivery routing. The value is `undefined` if the buyer hasn't entered\n * one yet or the country doesn't use postal codes.\n *\n * {% include /apps/checkout/privacy-icon.md %} Requires level 2 access to [protected customer data](/docs/apps/store/data-protection/protected-customer-data).\n *\n * @example 'K2P 2L8'\n */\n zip?: string;\n\n /**\n * The two-letter country code in [ISO 3166 Alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2)\n * format. The value is `undefined` if the buyer hasn't selected a country\n * yet.\n *\n * {% include /apps/checkout/privacy-icon.md %} Requires level 2 access to [protected customer data](/docs/apps/store/data-protection/protected-customer-data).\n *\n * @example 'CA' for Canada.\n */\n countryCode?: CountryCode;\n\n /**\n * The province, state, prefecture, or region code of the address. The\n * format varies by country. The value is `undefined` if the buyer hasn't\n * selected one yet or the country doesn't have provinces.\n *\n * {% include /apps/checkout/privacy-icon.md %} Requires level 2 access to [protected customer data](/docs/apps/store/data-protection/protected-customer-data).\n *\n * @example 'ON' for Ontario.\n */\n provinceCode?: string;\n\n /**\n * The phone number associated with the address, typically in international\n * format. The value is `undefined` if the buyer didn't provide a phone\n * number or the store doesn't collect phone numbers.\n *\n * {% include /apps/checkout/privacy-icon.md %} Requires level 2 access to [protected customer data](/docs/apps/store/data-protection/protected-customer-data).\n *\n * @example '+1 613 111 2222'\n */\n phone?: string;\n}"
356384
}
357385
},
358386
"CountryCode": {
@@ -8535,6 +8563,117 @@
85358563
"isPublicDocs": true
85368564
}
85378565
},
8566+
"AddressExtendedFields": {
8567+
"src/surfaces/customer-account/api/shared.ts": {
8568+
"filePath": "src/surfaces/customer-account/api/shared.ts",
8569+
"name": "AddressExtendedFields",
8570+
"description": "Structured extended address fields for countries and regions that collect address components separately from the flat address lines.",
8571+
"isPublicDocs": true,
8572+
"members": [
8573+
{
8574+
"filePath": "src/surfaces/customer-account/api/shared.ts",
8575+
"syntaxKind": "PropertySignature",
8576+
"name": "district",
8577+
"value": "string | null",
8578+
"description": "The district or neighborhood.",
8579+
"isOptional": true,
8580+
"examples": [
8581+
{
8582+
"title": "Example",
8583+
"description": "",
8584+
"tabs": [
8585+
{
8586+
"code": "'Bela Vista'",
8587+
"title": "Example"
8588+
}
8589+
]
8590+
}
8591+
]
8592+
},
8593+
{
8594+
"filePath": "src/surfaces/customer-account/api/shared.ts",
8595+
"syntaxKind": "PropertySignature",
8596+
"name": "line2",
8597+
"value": "string | null",
8598+
"description": "Additional address information, such as a block, floor, or unit.",
8599+
"isOptional": true,
8600+
"examples": [
8601+
{
8602+
"title": "Example",
8603+
"description": "",
8604+
"tabs": [
8605+
{
8606+
"code": "'10th floor'",
8607+
"title": "Example"
8608+
}
8609+
]
8610+
}
8611+
]
8612+
},
8613+
{
8614+
"filePath": "src/surfaces/customer-account/api/shared.ts",
8615+
"syntaxKind": "PropertySignature",
8616+
"name": "streetName",
8617+
"value": "string | null",
8618+
"description": "The street name without the building or street number.",
8619+
"isOptional": true,
8620+
"examples": [
8621+
{
8622+
"title": "Example",
8623+
"description": "",
8624+
"tabs": [
8625+
{
8626+
"code": "'Avenida Paulista'",
8627+
"title": "Example"
8628+
}
8629+
]
8630+
}
8631+
]
8632+
},
8633+
{
8634+
"filePath": "src/surfaces/customer-account/api/shared.ts",
8635+
"syntaxKind": "PropertySignature",
8636+
"name": "streetNumber",
8637+
"value": "string | null",
8638+
"description": "The building or street number.",
8639+
"isOptional": true,
8640+
"examples": [
8641+
{
8642+
"title": "Example",
8643+
"description": "",
8644+
"tabs": [
8645+
{
8646+
"code": "'123'",
8647+
"title": "Example"
8648+
}
8649+
]
8650+
}
8651+
]
8652+
},
8653+
{
8654+
"filePath": "src/surfaces/customer-account/api/shared.ts",
8655+
"syntaxKind": "PropertySignature",
8656+
"name": "subdistrict",
8657+
"value": "string | null",
8658+
"description": "The subdistrict or smaller locality.",
8659+
"isOptional": true,
8660+
"examples": [
8661+
{
8662+
"title": "Example",
8663+
"description": "",
8664+
"tabs": [
8665+
{
8666+
"code": "'Centro'",
8667+
"title": "Example"
8668+
}
8669+
]
8670+
}
8671+
]
8672+
}
8673+
],
8674+
"value": "export interface AddressExtendedFields {\n /**\n * The street name without the building or street number.\n *\n * @example 'Avenida Paulista'\n */\n streetName?: string | null;\n\n /**\n * The building or street number.\n *\n * @example '123'\n */\n streetNumber?: string | null;\n\n /**\n * Additional address information, such as a block, floor, or unit.\n *\n * @example '10th floor'\n */\n line2?: string | null;\n\n /**\n * The district or neighborhood.\n *\n * @example 'Bela Vista'\n */\n district?: string | null;\n\n /**\n * The subdistrict or smaller locality.\n *\n * @example 'Centro'\n */\n subdistrict?: string | null;\n}"
8675+
}
8676+
},
85388677
"AuthenticatedAccount": {
85398678
"src/surfaces/customer-account/api/shared.ts": {
85408679
"filePath": "src/surfaces/customer-account/api/shared.ts",
@@ -182672,4 +182811,4 @@
182672182811
"value": "export interface UrlFieldProps extends URLFieldElementProps, UrlFieldEvents {\n}"
182673182812
}
182674182813
}
182675-
}
182814+
}

packages/ui-extensions/src/surfaces/customer-account/api.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ export type {
5151
GraphQLError,
5252
SellingPlan,
5353
StorefrontApiVersion,
54+
AddressExtendedFields,
5455
MailingAddress,
5556
ApiVersion,
5657
Capability,

0 commit comments

Comments
 (0)