212 lines
8.0 KiB
TypeScript
212 lines
8.0 KiB
TypeScript
import { z } from 'zod';
|
|
import { ShopifyClient } from '../clients/shopify.js';
|
|
|
|
const ListThemesInput = z.object({
|
|
fields: z.string().optional().describe('Comma-separated list of fields to retrieve'),
|
|
role: z.enum(['main', 'unpublished', 'demo']).optional().describe('Filter by theme role'),
|
|
});
|
|
|
|
const GetThemeInput = z.object({
|
|
id: z.string().describe('Theme ID'),
|
|
fields: z.string().optional().describe('Comma-separated list of fields to retrieve'),
|
|
});
|
|
|
|
const CreateThemeInput = z.object({
|
|
name: z.string().describe('Theme name'),
|
|
src: z.string().optional().describe('URL to theme ZIP file'),
|
|
role: z.enum(['main', 'unpublished']).optional().describe('Theme role'),
|
|
});
|
|
|
|
const UpdateThemeInput = z.object({
|
|
id: z.string().describe('Theme ID'),
|
|
name: z.string().optional().describe('Theme name'),
|
|
role: z.enum(['main', 'unpublished']).optional().describe('Theme role'),
|
|
});
|
|
|
|
const DeleteThemeInput = z.object({
|
|
id: z.string().describe('Theme ID'),
|
|
});
|
|
|
|
const ListAssetsInput = z.object({
|
|
theme_id: z.string().describe('Theme ID'),
|
|
fields: z.string().optional().describe('Comma-separated list of fields to retrieve'),
|
|
});
|
|
|
|
const GetAssetInput = z.object({
|
|
theme_id: z.string().describe('Theme ID'),
|
|
asset_key: z.string().describe('Asset key (path, e.g., "templates/index.liquid")'),
|
|
});
|
|
|
|
const CreateOrUpdateAssetInput = z.object({
|
|
theme_id: z.string().describe('Theme ID'),
|
|
key: z.string().describe('Asset key (path, e.g., "templates/index.liquid")'),
|
|
value: z.string().optional().describe('Asset text content'),
|
|
src: z.string().optional().describe('Asset source URL (for binary assets)'),
|
|
attachment: z.string().optional().describe('Base64-encoded binary asset content'),
|
|
});
|
|
|
|
export default [
|
|
{
|
|
name: 'shopify_list_themes',
|
|
description: 'List all themes with optional role filtering',
|
|
inputSchema: {
|
|
type: 'object' as const,
|
|
properties: {
|
|
fields: { type: 'string', description: 'Comma-separated list of fields to retrieve' },
|
|
role: { type: 'string', enum: ['main', 'unpublished', 'demo'], description: 'Filter by theme role' },
|
|
},
|
|
},
|
|
handler: async (input: unknown, client: ShopifyClient) => {
|
|
const validated = ListThemesInput.parse(input);
|
|
const results = await client.list('/themes.json', { params: validated });
|
|
return {
|
|
content: [{ type: 'text' as const, text: JSON.stringify(results, null, 2) }],
|
|
};
|
|
},
|
|
},
|
|
{
|
|
name: 'shopify_get_theme',
|
|
description: 'Get a specific theme by ID',
|
|
inputSchema: {
|
|
type: 'object' as const,
|
|
properties: {
|
|
id: { type: 'string', description: 'Theme ID' },
|
|
fields: { type: 'string', description: 'Comma-separated list of fields to retrieve' },
|
|
},
|
|
required: ['id'],
|
|
},
|
|
handler: async (input: unknown, client: ShopifyClient) => {
|
|
const validated = GetThemeInput.parse(input);
|
|
const result = await client.get(`/themes/${validated.id}.json`, {
|
|
params: validated.fields ? { fields: validated.fields } : {},
|
|
});
|
|
return {
|
|
content: [{ type: 'text' as const, text: JSON.stringify(result, null, 2) }],
|
|
};
|
|
},
|
|
},
|
|
{
|
|
name: 'shopify_create_theme',
|
|
description: 'Create a new theme from a ZIP file',
|
|
inputSchema: {
|
|
type: 'object' as const,
|
|
properties: {
|
|
name: { type: 'string', description: 'Theme name' },
|
|
src: { type: 'string', description: 'URL to theme ZIP file' },
|
|
role: { type: 'string', enum: ['main', 'unpublished'], description: 'Theme role' },
|
|
},
|
|
required: ['name'],
|
|
},
|
|
handler: async (input: unknown, client: ShopifyClient) => {
|
|
const validated = CreateThemeInput.parse(input);
|
|
const result = await client.create('/themes.json', { theme: validated });
|
|
return {
|
|
content: [{ type: 'text' as const, text: JSON.stringify(result, null, 2) }],
|
|
};
|
|
},
|
|
},
|
|
{
|
|
name: 'shopify_update_theme',
|
|
description: 'Update an existing theme',
|
|
inputSchema: {
|
|
type: 'object' as const,
|
|
properties: {
|
|
id: { type: 'string', description: 'Theme ID' },
|
|
name: { type: 'string', description: 'Theme name' },
|
|
role: { type: 'string', enum: ['main', 'unpublished'], description: 'Theme role' },
|
|
},
|
|
required: ['id'],
|
|
},
|
|
handler: async (input: unknown, client: ShopifyClient) => {
|
|
const validated = UpdateThemeInput.parse(input);
|
|
const { id, ...updates } = validated;
|
|
const result = await client.update(`/themes/${id}.json`, { theme: updates });
|
|
return {
|
|
content: [{ type: 'text' as const, text: JSON.stringify(result, null, 2) }],
|
|
};
|
|
},
|
|
},
|
|
{
|
|
name: 'shopify_delete_theme',
|
|
description: 'Delete a theme by ID',
|
|
inputSchema: {
|
|
type: 'object' as const,
|
|
properties: {
|
|
id: { type: 'string', description: 'Theme ID' },
|
|
},
|
|
required: ['id'],
|
|
},
|
|
handler: async (input: unknown, client: ShopifyClient) => {
|
|
const validated = DeleteThemeInput.parse(input);
|
|
await client.delete(`/themes/${validated.id}.json`);
|
|
return {
|
|
content: [{ type: 'text' as const, text: `Theme ${validated.id} deleted successfully` }],
|
|
};
|
|
},
|
|
},
|
|
{
|
|
name: 'shopify_list_theme_assets',
|
|
description: 'List all assets in a theme',
|
|
inputSchema: {
|
|
type: 'object' as const,
|
|
properties: {
|
|
theme_id: { type: 'string', description: 'Theme ID' },
|
|
fields: { type: 'string', description: 'Comma-separated list of fields to retrieve' },
|
|
},
|
|
required: ['theme_id'],
|
|
},
|
|
handler: async (input: unknown, client: ShopifyClient) => {
|
|
const validated = ListAssetsInput.parse(input);
|
|
const { theme_id, ...params } = validated;
|
|
const results = await client.list(`/themes/${theme_id}/assets.json`, { params });
|
|
return {
|
|
content: [{ type: 'text' as const, text: JSON.stringify(results, null, 2) }],
|
|
};
|
|
},
|
|
},
|
|
{
|
|
name: 'shopify_get_theme_asset',
|
|
description: 'Get a specific theme asset by key',
|
|
inputSchema: {
|
|
type: 'object' as const,
|
|
properties: {
|
|
theme_id: { type: 'string', description: 'Theme ID' },
|
|
asset_key: { type: 'string', description: 'Asset key (path, e.g., "templates/index.liquid")' },
|
|
},
|
|
required: ['theme_id', 'asset_key'],
|
|
},
|
|
handler: async (input: unknown, client: ShopifyClient) => {
|
|
const validated = GetAssetInput.parse(input);
|
|
const result = await client.get(`/themes/${validated.theme_id}/assets.json`, {
|
|
params: { 'asset[key]': validated.asset_key },
|
|
});
|
|
return {
|
|
content: [{ type: 'text' as const, text: JSON.stringify(result, null, 2) }],
|
|
};
|
|
},
|
|
},
|
|
{
|
|
name: 'shopify_create_or_update_theme_asset',
|
|
description: 'Create or update a theme asset (text or binary)',
|
|
inputSchema: {
|
|
type: 'object' as const,
|
|
properties: {
|
|
theme_id: { type: 'string', description: 'Theme ID' },
|
|
key: { type: 'string', description: 'Asset key (path, e.g., "templates/index.liquid")' },
|
|
value: { type: 'string', description: 'Asset text content' },
|
|
src: { type: 'string', description: 'Asset source URL (for binary assets)' },
|
|
attachment: { type: 'string', description: 'Base64-encoded binary asset content' },
|
|
},
|
|
required: ['theme_id', 'key'],
|
|
},
|
|
handler: async (input: unknown, client: ShopifyClient) => {
|
|
const validated = CreateOrUpdateAssetInput.parse(input);
|
|
const { theme_id, ...assetData } = validated;
|
|
const result = await client.update(`/themes/${theme_id}/assets.json`, { asset: assetData });
|
|
return {
|
|
content: [{ type: 'text' as const, text: JSON.stringify(result, null, 2) }],
|
|
};
|
|
},
|
|
},
|
|
];
|