@porulle/adapter-shopify 0.77.1 → 0.78.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/catalog.d.ts CHANGED
@@ -8,9 +8,9 @@ import type { ShopifyGraphqlTarget } from "./graphql.js";
8
8
  * single-query ceiling while halving the number of calls a large catalogue takes.
9
9
  */
10
10
  export declare const CATALOG_PAGE_PRODUCTS = 50;
11
- export declare const CATALOG_PAGE_QUERY = "query PorulleCatalogPage($first: Int!, $after: String) {\n shop { currencyCode }\n products(first: $first, after: $after, sortKey: ID) { pageInfo { hasNextPage endCursor } nodes { \n legacyResourceId title handle status descriptionHtml vendor productType tags onlineStoreUrl\n category { name }\n options { name position optionValues { name } }\n media(first: 20) { nodes { id alt mediaContentType ... on MediaImage { image { url } } } }\n variants(first: 25) { pageInfo { hasNextPage endCursor } nodes { \n legacyResourceId sku price compareAtPrice inventoryQuantity\n barcodes(first: 1) { nodes { value } }\n selectedOptions { name value }\n media(first: 1) { nodes { id } }\n inventoryItem { legacyResourceId measurement { weight { unit value } } } } } } }\n}";
11
+ export declare const CATALOG_PAGE_QUERY = "query PorulleCatalogPage($first: Int!, $after: String) {\n shop { currencyCode }\n products(first: $first, after: $after, sortKey: ID) { pageInfo { hasNextPage endCursor } nodes { \n legacyResourceId title handle status descriptionHtml vendor productType tags onlineStoreUrl\n category { id name }\n options { name position optionValues { name } }\n media(first: 20) { nodes { id alt mediaContentType ... on MediaImage { image { url } } } }\n variants(first: 25) { pageInfo { hasNextPage endCursor } nodes { \n legacyResourceId sku price compareAtPrice inventoryQuantity\n barcodes(first: 1) { nodes { value } }\n selectedOptions { name value }\n media(first: 1) { nodes { id } }\n inventoryItem { legacyResourceId measurement { weight { unit value } } } } } } }\n}";
12
12
  export declare const VARIANTS_PAGE_QUERY = "query PorulleProductVariants($id: ID!, $after: String) {\n product(id: $id) { variants(first: 250, after: $after) { pageInfo { hasNextPage endCursor } nodes { \n legacyResourceId sku price compareAtPrice inventoryQuantity\n barcodes(first: 1) { nodes { value } }\n selectedOptions { name value }\n media(first: 1) { nodes { id } }\n inventoryItem { legacyResourceId measurement { weight { unit value } } } } } }\n}";
13
- export declare const CATALOG_ITEMS_QUERY = "query PorulleCatalogItems($ids: [ID!]!) {\n shop { currencyCode }\n nodes(ids: $ids) { ... on Product { \n legacyResourceId title handle status descriptionHtml vendor productType tags onlineStoreUrl\n category { name }\n options { name position optionValues { name } }\n media(first: 20) { nodes { id alt mediaContentType ... on MediaImage { image { url } } } }\n variants(first: 25) { pageInfo { hasNextPage endCursor } nodes { \n legacyResourceId sku price compareAtPrice inventoryQuantity\n barcodes(first: 1) { nodes { value } }\n selectedOptions { name value }\n media(first: 1) { nodes { id } }\n inventoryItem { legacyResourceId measurement { weight { unit value } } } } } } }\n}";
13
+ export declare const CATALOG_ITEMS_QUERY = "query PorulleCatalogItems($ids: [ID!]!) {\n shop { currencyCode }\n nodes(ids: $ids) { ... on Product { \n legacyResourceId title handle status descriptionHtml vendor productType tags onlineStoreUrl\n category { id name }\n options { name position optionValues { name } }\n media(first: 20) { nodes { id alt mediaContentType ... on MediaImage { image { url } } } }\n variants(first: 25) { pageInfo { hasNextPage endCursor } nodes { \n legacyResourceId sku price compareAtPrice inventoryQuantity\n barcodes(first: 1) { nodes { value } }\n selectedOptions { name value }\n media(first: 1) { nodes { id } }\n inventoryItem { legacyResourceId measurement { weight { unit value } } } } } } }\n}";
14
14
  declare const variantSchema: z.ZodObject<{
15
15
  legacyResourceId: z.ZodString;
16
16
  sku: z.ZodNullable<z.ZodString>;
@@ -53,6 +53,7 @@ declare const productSchema: z.ZodObject<{
53
53
  tags: z.ZodArray<z.ZodString>;
54
54
  onlineStoreUrl: z.ZodNullable<z.ZodString>;
55
55
  category: z.ZodNullable<z.ZodObject<{
56
+ id: z.ZodString;
56
57
  name: z.ZodString;
57
58
  }, z.core.$strip>>;
58
59
  options: z.ZodArray<z.ZodObject<{
@@ -130,6 +131,7 @@ export declare const catalogPageSchema: z.ZodObject<{
130
131
  tags: z.ZodArray<z.ZodString>;
131
132
  onlineStoreUrl: z.ZodNullable<z.ZodString>;
132
133
  category: z.ZodNullable<z.ZodObject<{
134
+ id: z.ZodString;
133
135
  name: z.ZodString;
134
136
  }, z.core.$strip>>;
135
137
  options: z.ZodArray<z.ZodObject<{
package/dist/catalog.js CHANGED
@@ -20,7 +20,7 @@ const VARIANT_FIELDS = `
20
20
  inventoryItem { legacyResourceId measurement { weight { unit value } } }`;
21
21
  const PRODUCT_FIELDS = `
22
22
  legacyResourceId title handle status descriptionHtml vendor productType tags onlineStoreUrl
23
- category { name }
23
+ category { id name }
24
24
  options { name position optionValues { name } }
25
25
  media(first: ${MEDIA_PER_PRODUCT}) { nodes { id alt mediaContentType ... on MediaImage { image { url } } } }
26
26
  variants(first: ${VARIANTS_WITH_PRODUCT}) { pageInfo { hasNextPage endCursor } nodes { ${VARIANT_FIELDS} } }`;
@@ -61,7 +61,7 @@ const productSchema = z.object({
61
61
  productType: z.string(),
62
62
  tags: z.array(z.string()),
63
63
  onlineStoreUrl: z.string().nullable(),
64
- category: z.object({ name: z.string() }).nullable(),
64
+ category: z.object({ id: z.string(), name: z.string() }).nullable(),
65
65
  options: z.array(z.object({ name: z.string(), position: z.number(), optionValues: z.array(z.object({ name: z.string() })) })),
66
66
  media: z.object({
67
67
  nodes: z.array(z.object({
@@ -119,10 +119,18 @@ function catalogStatus(status) {
119
119
  function slugify(value) {
120
120
  return value.toLowerCase().trim().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
121
121
  }
122
+ /** `gid://shopify/TaxonomyCategory/aa-1-4` → `aa-1-4`, the Standard Product Taxonomy's own id. */
123
+ function taxonomyCategoryId(gid) {
124
+ const id = gid.slice(gid.lastIndexOf("/") + 1);
125
+ return /^[a-z]{2}(-\d+)*$/.test(id) ? id : undefined;
126
+ }
122
127
  export function toCatalogItem(product, variants, currency) {
123
128
  const images = product.media.nodes.flatMap((media) => (media.mediaContentType === "IMAGE" && media.image ? [{ id: media.id, url: media.image.url, alt: media.alt }] : []));
124
129
  const category = product.productType ? slugify(product.productType) : product.category ? slugify(product.category.name) : "";
125
130
  const storefrontUrl = product.onlineStoreUrl;
131
+ // The merchant's (or Shopify's) Standard Product Taxonomy category, as Shopify's own id. A
132
+ // platform that classifies against the same taxonomy reads it instead of guessing from text.
133
+ const shopifyCategory = product.category ? taxonomyCategoryId(product.category.id) : undefined;
126
134
  return {
127
135
  externalId: product.legacyResourceId,
128
136
  slug: product.handle,
@@ -164,6 +172,7 @@ export function toCatalogItem(product, variants, currency) {
164
172
  // Only Shopify's own answer. Null means the product is not on the Online Store channel; a URL
165
173
  // assembled from the handle would be a guess that 404s on any shop with a custom route.
166
174
  ...(storefrontUrl ? { storefrontUrl } : {}),
175
+ ...(shopifyCategory ? { metadata: { shopifyTaxonomyCategoryId: shopifyCategory } } : {}),
167
176
  };
168
177
  }
169
178
  /** Every variant of `product`: the ones read with it, then the rest a page at a time. */