import { clampInt, nodesFromConnection, pageInfoFromConnection, shopifyGraphql, trimString, } from './lib/client.ts' import { PAGE_INFO_FIELDS } from './lib/fragments.ts' import { toGid } from './lib/shop.ts' import type { ShopifyClientOptions, ShopifyPageInfo } from './types.ts' export type CollectionSummary = { id: string title: string handle: string | null updatedAt: string | null sortOrder: string | null productsCount: number | null } export type ListCollectionsParams = ShopifyClientOptions & { query?: string first?: number after?: string } function mapCollection(node: Record): CollectionSummary { const count = node.productsCount && typeof node.productsCount === 'object' ? (node.productsCount as { count?: unknown }).count : node.productsCount return { id: String(node.id || ''), title: String(node.title || ''), handle: typeof node.handle === 'string' ? node.handle : null, updatedAt: typeof node.updatedAt === 'string' ? node.updatedAt : null, sortOrder: typeof node.sortOrder === 'string' ? node.sortOrder : null, productsCount: typeof count === 'number' ? count : null, } } /** * List collections (custom and smart). * * @example * import { listCollections } from 'kody:@kody/shopify/collections' * const { items } = await listCollections({ shop: 'acme', first: 20 }) */ export async function listCollections(params: ListCollectionsParams = {}) { const first = clampInt(params.first, 1, 50, 20) const data = await shopifyGraphql<{ collections: unknown }>({ shop: params.shop, apiVersion: params.apiVersion, query: `query ListCollections($first: Int!, $after: String, $query: String) { collections(first: $first, after: $after, query: $query) { ${PAGE_INFO_FIELDS} nodes { id title handle updatedAt sortOrder productsCount { count } } } }`, variables: { first, after: trimString(params.after) || null, query: trimString(params.query) || null, }, }) return { items: nodesFromConnection>(data.collections).map( mapCollection, ), pageInfo: pageInfoFromConnection(data.collections) as ShopifyPageInfo, } } /** * Get one collection and a page of its products. */ export async function getCollection( params: ShopifyClientOptions & { id: string productFirst?: number }, ) { const id = toGid('Collection', params.id) const productFirst = clampInt(params.productFirst, 1, 50, 10) const data = await shopifyGraphql<{ collection: (Record & { products?: unknown }) | null }>({ shop: params.shop, apiVersion: params.apiVersion, query: `query GetCollection($id: ID!, $productFirst: Int!) { collection(id: $id) { id title handle updatedAt sortOrder description productsCount { count } products(first: $productFirst) { nodes { id title handle status } } } }`, variables: { id, productFirst }, }) if (!data.collection) throw new Error(`Collection not found: ${id}`) const collection = mapCollection(data.collection) return { ...collection, description: typeof data.collection.description === 'string' ? data.collection.description : null, products: nodesFromConnection>( data.collection.products, ).map((node) => ({ id: String(node.id || ''), title: String(node.title || ''), handle: typeof node.handle === 'string' ? node.handle : null, status: typeof node.status === 'string' ? node.status : null, })), } } /** Default export: list collections. */ export default listCollections