@sommpicks/sommpicks-shopify 24.12.15 → 24.12.17
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/shopify/product/ShopifyProductPublicationsService.d.ts +8 -0
- package/dist/shopify/product/ShopifyProductPublicationsService.d.ts.map +1 -1
- package/dist/shopify/product/ShopifyProductPublicationsService.js +61 -0
- package/dist/shopify/product/ShopifyProductPublicationsService.js.map +1 -1
- package/package.json +4 -2
- package/shopify/product/ShopifyProductPublicationsService.ts +60 -0
|
@@ -18,6 +18,14 @@ export declare class ShopifyProductPublicationsService extends AbstractService {
|
|
|
18
18
|
* @returns {IProductPublishResult}
|
|
19
19
|
*/
|
|
20
20
|
publish: (productId: number) => Promise<IProductPublishResult>;
|
|
21
|
+
/**
|
|
22
|
+
* Publishes multiple products to all publication channels in a single GraphQL request.
|
|
23
|
+
* More efficient than calling publish() multiple times.
|
|
24
|
+
*
|
|
25
|
+
* @param {number[]} productIds Array of Shopify product IDs to publish
|
|
26
|
+
* @returns {IProductPublishResult[]} Array of publish results
|
|
27
|
+
*/
|
|
28
|
+
publishBatch: (productIds: number[]) => Promise<IProductPublishResult[]>;
|
|
21
29
|
/**
|
|
22
30
|
* Unpublishes product to all publication channels.
|
|
23
31
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ShopifyProductPublicationsService.d.ts","sourceRoot":"","sources":["../../../shopify/product/ShopifyProductPublicationsService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAItC,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAG1D,qBAAa,iCAAkC,SAAQ,eAAe;IAKtD,OAAO,CAAC,aAAa;IAHjC,OAAO,CAAC,MAAM,CAAC,iBAAiB,CAA4E;IAC5G,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAkB;gBAEhC,aAAa,EAAE,aAAa;IAEhD;;;;OAIG;IACI,eAAe,QAAa,QAAQ,oBAAoB,EAAE,CAAC,CAgChE;IAEF;;;;;OAKG;IACI,OAAO,cAAqB,MAAM,KAAG,QAAQ,qBAAqB,CAAC,CA+BxE;IAEF;;;;;OAKG;IACI,SAAS,cAAqB,MAAM,KAAG,QAAQ,uBAAuB,CAAC,CAuB5E;CACL"}
|
|
1
|
+
{"version":3,"file":"ShopifyProductPublicationsService.d.ts","sourceRoot":"","sources":["../../../shopify/product/ShopifyProductPublicationsService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAItC,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAG1D,qBAAa,iCAAkC,SAAQ,eAAe;IAKtD,OAAO,CAAC,aAAa;IAHjC,OAAO,CAAC,MAAM,CAAC,iBAAiB,CAA4E;IAC5G,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAkB;gBAEhC,aAAa,EAAE,aAAa;IAEhD;;;;OAIG;IACI,eAAe,QAAa,QAAQ,oBAAoB,EAAE,CAAC,CAgChE;IAEF;;;;;OAKG;IACI,OAAO,cAAqB,MAAM,KAAG,QAAQ,qBAAqB,CAAC,CA+BxE;IAEF;;;;;;OAMG;IACI,YAAY,eAAsB,MAAM,EAAE,KAAG,QAAQ,qBAAqB,EAAE,CAAC,CAmDlF;IAEF;;;;;OAKG;IACI,SAAS,cAAqB,MAAM,KAAG,QAAQ,uBAAuB,CAAC,CAuB5E;CACL"}
|
|
@@ -102,6 +102,67 @@ class ShopifyProductPublicationsService extends AbstractService_1.AbstractServic
|
|
|
102
102
|
this.logErrorAndThrow(error);
|
|
103
103
|
}
|
|
104
104
|
});
|
|
105
|
+
/**
|
|
106
|
+
* Publishes multiple products to all publication channels in a single GraphQL request.
|
|
107
|
+
* More efficient than calling publish() multiple times.
|
|
108
|
+
*
|
|
109
|
+
* @param {number[]} productIds Array of Shopify product IDs to publish
|
|
110
|
+
* @returns {IProductPublishResult[]} Array of publish results
|
|
111
|
+
*/
|
|
112
|
+
this.publishBatch = (productIds) => __awaiter(this, void 0, void 0, function* () {
|
|
113
|
+
var _a, _b;
|
|
114
|
+
try {
|
|
115
|
+
if (!productIds || productIds.length === 0) {
|
|
116
|
+
return [];
|
|
117
|
+
}
|
|
118
|
+
Logger_1.Logger.info(`Publishing batch of ${productIds.length} products: ${productIds.join(', ')}`);
|
|
119
|
+
const publications = yield this.getPublications();
|
|
120
|
+
const publicationInputs = publications.map(p => ({ publicationId: p.id }));
|
|
121
|
+
// Build individual mutations for each product
|
|
122
|
+
const mutations = productIds.map((productId, index) => {
|
|
123
|
+
const gqlId = this.getGraphProductIdFromId(productId);
|
|
124
|
+
return `
|
|
125
|
+
publish${index}: productPublish(input: {
|
|
126
|
+
id: "${gqlId}",
|
|
127
|
+
productPublications: [${publicationInputs.map(p => `{publicationId: "${p.publicationId}"}`).join(', ')}]
|
|
128
|
+
}) {
|
|
129
|
+
product { id }
|
|
130
|
+
productPublications {
|
|
131
|
+
isPublished
|
|
132
|
+
channel { name }
|
|
133
|
+
}
|
|
134
|
+
userErrors { field message }
|
|
135
|
+
}
|
|
136
|
+
`;
|
|
137
|
+
}).join('\n');
|
|
138
|
+
const query = `mutation { ${mutations} }`;
|
|
139
|
+
const response = yield this.axiosInstance.post('/graphql.json', { query }, { query_cost: productIds.length * 10 });
|
|
140
|
+
if (response && response.data && response.data.data) {
|
|
141
|
+
const results = [];
|
|
142
|
+
for (let i = 0; i < productIds.length; i++) {
|
|
143
|
+
const key = `publish${i}`;
|
|
144
|
+
const publishResult = response.data.data[key];
|
|
145
|
+
if ((_a = publishResult === null || publishResult === void 0 ? void 0 : publishResult.product) === null || _a === void 0 ? void 0 : _a.id) {
|
|
146
|
+
const productPublications = publishResult.productPublications || [];
|
|
147
|
+
results.push({
|
|
148
|
+
id: productIds[i],
|
|
149
|
+
productPublications: productPublications.filter((pp) => pp.isPublished).map((pp) => pp.channel)
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
else if (((_b = publishResult === null || publishResult === void 0 ? void 0 : publishResult.userErrors) === null || _b === void 0 ? void 0 : _b.length) > 0) {
|
|
153
|
+
Logger_1.Logger.error(`Batch publish error for product ${productIds[i]}: ${JSON.stringify(publishResult.userErrors)}`);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return results;
|
|
157
|
+
}
|
|
158
|
+
else {
|
|
159
|
+
throw new InspiraShopifyError_1.default({ message: JSON.stringify(response.data.errors) });
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
catch (error) {
|
|
163
|
+
this.logErrorAndThrow(error);
|
|
164
|
+
}
|
|
165
|
+
});
|
|
105
166
|
/**
|
|
106
167
|
* Unpublishes product to all publication channels.
|
|
107
168
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ShopifyProductPublicationsService.js","sourceRoot":"","sources":["../../../shopify/product/ShopifyProductPublicationsService.ts"],"names":[],"mappings":";;;;;;;;;;;;AACA,qCAAgC;AAChC,6CAA8B;AAC9B,yCAAsC;AACtC,6DAA0D;AAC1D,uEAAgE;AAEhE,MAAa,iCAAkC,SAAQ,iCAAe;IAKlE,YAAoB,aAA4B;QAAI,KAAK,EAAE,CAAC;QAAxC,kBAAa,GAAb,aAAa,CAAe;QAEhD;;;;WAIG;QACI,oBAAe,GAAG,GAA0C,EAAE;YACjE,IAAI;gBACA,eAAM,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAC;gBACxC,MAAM,MAAM,GAAG,iCAAiC,CAAC,iBAAiB,CAAC;gBACnE,IAAI,MAAM,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC,SAAS,GAAG,iCAAiC,CAAC,UAAU,EAAE;oBACxF,OAAO,MAAM,CAAC,YAAY,CAAC;iBAC9B;gBACD,MAAM,KAAK,GAAG,IAAA,qBAAG,EAAA;;;;;;;;;;;cAWf,CAAC;gBACH,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,eAAe,EAAE,EAAE,KAAK,EAAE,IAAA,eAAK,EAAC,KAAK,CAAC,EAAE,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC,CAAC;gBAC7G,IAAI,QAAQ,IAAI,QAAQ,CAAC,IAAI,IAAI,QAAQ,CAAC,IAAI,CAAC,IAAI,IAAI,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE;oBACpF,MAAM,wBAAwB,GAAqC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC;oBACzG,MAAM,mBAAmB,GAA2B,wBAAwB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;oBAChG,iCAAiC,CAAC,iBAAiB,GAAG;wBAClD,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;wBACrB,YAAY,EAAE,mBAAmB;qBACpC,CAAC;oBACF,OAAO,mBAAmB,CAAC;iBAC9B;qBAAM;oBACH,MAAM,IAAI,6BAAmB,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;iBACpF;aACJ;YAAC,OAAO,KAAK,EAAE;gBAAE,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC;aAAE;QACrD,CAAC,CAAA,CAAC;QAEF;;;;;WAKG;QACI,YAAO,GAAG,CAAO,SAAiB,EAAkC,EAAE;YACzE,IAAI;gBACA,eAAM,CAAC,IAAI,CAAC,2BAA2B,SAAS,sBAAsB,CAAC,CAAC;gBACxE,MAAM,YAAY,GAAG,IAAA,qBAAG,EAAA;;;;;;;;;;;;;;;;cAgBtB,CAAC;gBACH,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,eAAe,EAAE,CAAC;gBAClD,MAAM,WAAW,GAAG,EAAE,EAAE,EAAE,IAAI,CAAC,uBAAuB,CAAC,SAAS,CAAC,EAAE,mBAAmB,EAAE,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,aAAa,EAAE,CAAC,CAAC,EAAE,EAAC,CAAC,CAAC,EAAE,CAAC;gBAC1I,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,eAAe,EAAE,EAAE,KAAK,EAAE,IAAA,eAAK,EAAC,YAAY,CAAC,EAAE,SAAS,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,EAAE,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC,CAAC;gBACvJ,IAAI,QAAQ,IAAI,QAAQ,CAAC,IAAI,IAAI,QAAQ,CAAC,IAAI,CAAC,IAAI,IAAI,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE;oBACtF,MAAM,mBAAmB,GAA0D,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,mBAAmB,CAAC;oBAEzI,OAAO,EAAE,EAAE,EAAE,SAAS,EAAE,mBAAmB,EAAE,mBAAmB,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;iBACzH;qBAAM;oBACH,MAAM,IAAI,6BAAmB,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;iBACpF;aACJ;YAAC,OAAO,KAAK,EAAE;gBAAE,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC;aAAE;QACrD,CAAC,CAAA,CAAC;QAEF;;;;;WAKG;QACI,cAAS,GAAG,CAAO,SAAiB,EAAoC,EAAE;YAC7E,IAAI;gBACA,eAAM,CAAC,IAAI,CAAC,6BAA6B,SAAS,sBAAsB,CAAC,CAAC;gBAC1E,MAAM,YAAY,GAAG,IAAA,qBAAG,EAAA;;;;;;;;;;cAUtB,CAAC;gBACH,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,eAAe,EAAE,CAAC;gBAClD,MAAM,WAAW,GAAG,EAAE,EAAE,EAAE,IAAI,CAAC,uBAAuB,CAAC,SAAS,CAAC,EAAE,mBAAmB,EAAE,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,aAAa,EAAE,CAAC,CAAC,EAAE,EAAC,CAAC,CAAC,EAAE,CAAC;gBAC1I,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,eAAe,EAAE,EAAE,KAAK,EAAE,IAAA,eAAK,EAAC,YAAY,CAAC,EAAE,SAAS,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,EAAE,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC,CAAC;gBACvJ,IAAI,QAAQ,IAAI,QAAQ,CAAC,IAAI,IAAI,QAAQ,CAAC,IAAI,CAAC,IAAI,IAAI,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE;oBACxF,OAAO,EAAE,EAAE,EAAE,SAAS,EAAE,CAAC;iBAC5B;qBAAM;oBACH,MAAM,IAAI,6BAAmB,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;iBACpF;aACJ;YAAC,OAAO,KAAK,EAAE;gBAAE,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC;aAAE;QACrD,CAAC,CAAA,CAAC;IA7G2D,CAAC;;AALlE,8EAmHC;AAjHkB,mDAAiB,GAAuE,IAAI,CAAC;AACpF,4CAAU,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC","sourcesContent":["import { AxiosInstance } from 'axios';\nimport { print } from 'graphql';\nimport gql from 'graphql-tag';\nimport { Logger } from '../../Logger';\nimport { AbstractService } from '../base/AbstractService';\nimport InspiraShopifyError from '../errors/InspiraShopifyError';\n\nexport class ShopifyProductPublicationsService extends AbstractService {\n\n private static publicationsCache: { fetchedAt: number; publications: IProductPublications[] } | null = null;\n private static readonly cacheTtlMs = 30 * 60 * 1000;\n\n constructor(private axiosInstance: AxiosInstance) { super(); }\n\n /**\n * Returns a max of 15 publications\n * \n * @returns {IProductPublications[]} list of publications in store.\n */\n public getPublications = async (): Promise<IProductPublications[]> => {\n try {\n Logger.info('Get product publications');\n const cached = ShopifyProductPublicationsService.publicationsCache;\n if (cached && Date.now() - cached.fetchedAt < ShopifyProductPublicationsService.cacheTtlMs) {\n return cached.publications;\n }\n const query = gql`{\n publications(first: 15) {\n edges {\n node {\n id\n name\n autoPublish\n supportsFuturePublishing\n }\n }\n }\n }`;\n const response = await this.axiosInstance.post('/graphql.json', { query: print(query) }, { query_cost: 15 });\n if (response && response.data && response.data.data && response.data.data.publications) {\n const productPublicationsGraph: { node: IProductPublications }[] = response.data.data.publications.edges;\n const productPublications: IProductPublications[] = productPublicationsGraph.map((p) => p.node);\n ShopifyProductPublicationsService.publicationsCache = {\n fetchedAt: Date.now(),\n publications: productPublications\n };\n return productPublications;\n } else {\n throw new InspiraShopifyError({ message: JSON.stringify(response.data.errors) });\n }\n } catch (error) { this.logErrorAndThrow(error); }\n };\n \n /**\n * Publishes product to all publication channels.\n * \n * @param {number} productId \n * @returns {IProductPublishResult}\n */\n public publish = async (productId: number): Promise<IProductPublishResult> => {\n try {\n Logger.info(`Publish product with id ${productId} to all publications`);\n const publishQuery = gql`mutation productPublish($input: ProductPublishInput!) {\n productPublish(input: $input) {\n product {\n id\n }\n productPublications {\n isPublished\n channel {\n name\n }\n }\n userErrors {\n field\n message\n }\n }\n }`;\n const publications = await this.getPublications();\n const inputParams = { id: this.getGraphProductIdFromId(productId), productPublications: publications.map(p => ({ publicationId: p.id})) };\n const response = await this.axiosInstance.post('/graphql.json', { query: print(publishQuery), variables: { input: inputParams } }, { query_cost: 10 });\n if (response && response.data && response.data.data && response.data.data.productPublish) {\n const productPublications: { isPublished: boolean; channel: { name: string;} } []= response.data.data.productPublish.productPublications;\n \n return { id: productId, productPublications: productPublications.filter(pp => pp.isPublished).map(pp => pp.channel) };\n } else {\n throw new InspiraShopifyError({ message: JSON.stringify(response.data.errors) });\n }\n } catch (error) { this.logErrorAndThrow(error); }\n };\n\n /**\n * Unpublishes product to all publication channels.\n * \n * @param {number} productId \n * @returns {IProductUnpublishResult}\n */\n public unPublish = async (productId: number): Promise<IProductUnpublishResult> => {\n try {\n Logger.info(`Unpublish product with id ${productId} to all publications`);\n const publishQuery = gql`mutation productUnpublish($input: ProductUnpublishInput!) {\n productUnpublish(input: $input) {\n product {\n id\n }\n userErrors {\n field\n message\n }\n }\n }`;\n const publications = await this.getPublications();\n const inputParams = { id: this.getGraphProductIdFromId(productId), productPublications: publications.map(p => ({ publicationId: p.id})) };\n const response = await this.axiosInstance.post('/graphql.json', { query: print(publishQuery), variables: { input: inputParams } }, { query_cost: 10 });\n if (response && response.data && response.data.data && response.data.data.productUnpublish) {\n return { id: productId };\n } else {\n throw new InspiraShopifyError({ message: JSON.stringify(response.data.errors) });\n }\n } catch (error) { this.logErrorAndThrow(error); }\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"ShopifyProductPublicationsService.js","sourceRoot":"","sources":["../../../shopify/product/ShopifyProductPublicationsService.ts"],"names":[],"mappings":"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","sourcesContent":["import { AxiosInstance } from 'axios';\nimport { print } from 'graphql';\nimport gql from 'graphql-tag';\nimport { Logger } from '../../Logger';\nimport { AbstractService } from '../base/AbstractService';\nimport InspiraShopifyError from '../errors/InspiraShopifyError';\n\nexport class ShopifyProductPublicationsService extends AbstractService {\n\n private static publicationsCache: { fetchedAt: number; publications: IProductPublications[] } | null = null;\n private static readonly cacheTtlMs = 30 * 60 * 1000;\n\n constructor(private axiosInstance: AxiosInstance) { super(); }\n\n /**\n * Returns a max of 15 publications\n * \n * @returns {IProductPublications[]} list of publications in store.\n */\n public getPublications = async (): Promise<IProductPublications[]> => {\n try {\n Logger.info('Get product publications');\n const cached = ShopifyProductPublicationsService.publicationsCache;\n if (cached && Date.now() - cached.fetchedAt < ShopifyProductPublicationsService.cacheTtlMs) {\n return cached.publications;\n }\n const query = gql`{\n publications(first: 15) {\n edges {\n node {\n id\n name\n autoPublish\n supportsFuturePublishing\n }\n }\n }\n }`;\n const response = await this.axiosInstance.post('/graphql.json', { query: print(query) }, { query_cost: 15 });\n if (response && response.data && response.data.data && response.data.data.publications) {\n const productPublicationsGraph: { node: IProductPublications }[] = response.data.data.publications.edges;\n const productPublications: IProductPublications[] = productPublicationsGraph.map((p) => p.node);\n ShopifyProductPublicationsService.publicationsCache = {\n fetchedAt: Date.now(),\n publications: productPublications\n };\n return productPublications;\n } else {\n throw new InspiraShopifyError({ message: JSON.stringify(response.data.errors) });\n }\n } catch (error) { this.logErrorAndThrow(error); }\n };\n \n /**\n * Publishes product to all publication channels.\n * \n * @param {number} productId \n * @returns {IProductPublishResult}\n */\n public publish = async (productId: number): Promise<IProductPublishResult> => {\n try {\n Logger.info(`Publish product with id ${productId} to all publications`);\n const publishQuery = gql`mutation productPublish($input: ProductPublishInput!) {\n productPublish(input: $input) {\n product {\n id\n }\n productPublications {\n isPublished\n channel {\n name\n }\n }\n userErrors {\n field\n message\n }\n }\n }`;\n const publications = await this.getPublications();\n const inputParams = { id: this.getGraphProductIdFromId(productId), productPublications: publications.map(p => ({ publicationId: p.id})) };\n const response = await this.axiosInstance.post('/graphql.json', { query: print(publishQuery), variables: { input: inputParams } }, { query_cost: 10 });\n if (response && response.data && response.data.data && response.data.data.productPublish) {\n const productPublications: { isPublished: boolean; channel: { name: string;} } []= response.data.data.productPublish.productPublications;\n \n return { id: productId, productPublications: productPublications.filter(pp => pp.isPublished).map(pp => pp.channel) };\n } else {\n throw new InspiraShopifyError({ message: JSON.stringify(response.data.errors) });\n }\n } catch (error) { this.logErrorAndThrow(error); }\n };\n\n /**\n * Publishes multiple products to all publication channels in a single GraphQL request.\n * More efficient than calling publish() multiple times.\n * \n * @param {number[]} productIds Array of Shopify product IDs to publish\n * @returns {IProductPublishResult[]} Array of publish results\n */\n public publishBatch = async (productIds: number[]): Promise<IProductPublishResult[]> => {\n try {\n if (!productIds || productIds.length === 0) {\n return [];\n }\n \n Logger.info(`Publishing batch of ${productIds.length} products: ${productIds.join(', ')}`);\n const publications = await this.getPublications();\n const publicationInputs = publications.map(p => ({ publicationId: p.id }));\n \n // Build individual mutations for each product\n const mutations = productIds.map((productId, index) => {\n const gqlId = this.getGraphProductIdFromId(productId);\n return `\n publish${index}: productPublish(input: {\n id: \"${gqlId}\",\n productPublications: [${publicationInputs.map(p => `{publicationId: \"${p.publicationId}\"}`).join(', ')}]\n }) {\n product { id }\n productPublications {\n isPublished\n channel { name }\n }\n userErrors { field message }\n }\n `;\n }).join('\\n');\n \n const query = `mutation { ${mutations} }`;\n const response = await this.axiosInstance.post('/graphql.json', { query }, { query_cost: productIds.length * 10 });\n \n if (response && response.data && response.data.data) {\n const results: IProductPublishResult[] = [];\n for (let i = 0; i < productIds.length; i++) {\n const key = `publish${i}`;\n const publishResult = response.data.data[key];\n if (publishResult?.product?.id) {\n const productPublications = publishResult.productPublications || [];\n results.push({\n id: productIds[i],\n productPublications: productPublications.filter((pp: any) => pp.isPublished).map((pp: any) => pp.channel)\n });\n } else if (publishResult?.userErrors?.length > 0) {\n Logger.error(`Batch publish error for product ${productIds[i]}: ${JSON.stringify(publishResult.userErrors)}`);\n }\n }\n return results;\n } else {\n throw new InspiraShopifyError({ message: JSON.stringify(response.data.errors) });\n }\n } catch (error) { this.logErrorAndThrow(error); }\n };\n\n /**\n * Unpublishes product to all publication channels.\n * \n * @param {number} productId \n * @returns {IProductUnpublishResult}\n */\n public unPublish = async (productId: number): Promise<IProductUnpublishResult> => {\n try {\n Logger.info(`Unpublish product with id ${productId} to all publications`);\n const publishQuery = gql`mutation productUnpublish($input: ProductUnpublishInput!) {\n productUnpublish(input: $input) {\n product {\n id\n }\n userErrors {\n field\n message\n }\n }\n }`;\n const publications = await this.getPublications();\n const inputParams = { id: this.getGraphProductIdFromId(productId), productPublications: publications.map(p => ({ publicationId: p.id})) };\n const response = await this.axiosInstance.post('/graphql.json', { query: print(publishQuery), variables: { input: inputParams } }, { query_cost: 10 });\n if (response && response.data && response.data.data && response.data.data.productUnpublish) {\n return { id: productId };\n } else {\n throw new InspiraShopifyError({ message: JSON.stringify(response.data.errors) });\n }\n } catch (error) { this.logErrorAndThrow(error); }\n };\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sommpicks/sommpicks-shopify",
|
|
3
|
-
"version": "24.12.
|
|
4
|
-
"publishConfig": {
|
|
3
|
+
"version": "24.12.17",
|
|
4
|
+
"publishConfig": {
|
|
5
|
+
"access": "restricted"
|
|
6
|
+
},
|
|
5
7
|
"description": "Shopify REST API & GraphQL calls",
|
|
6
8
|
"main": "dist/index.js",
|
|
7
9
|
"types": "dist/indexBuild.d.ts",
|
|
@@ -90,6 +90,66 @@ export class ShopifyProductPublicationsService extends AbstractService {
|
|
|
90
90
|
} catch (error) { this.logErrorAndThrow(error); }
|
|
91
91
|
};
|
|
92
92
|
|
|
93
|
+
/**
|
|
94
|
+
* Publishes multiple products to all publication channels in a single GraphQL request.
|
|
95
|
+
* More efficient than calling publish() multiple times.
|
|
96
|
+
*
|
|
97
|
+
* @param {number[]} productIds Array of Shopify product IDs to publish
|
|
98
|
+
* @returns {IProductPublishResult[]} Array of publish results
|
|
99
|
+
*/
|
|
100
|
+
public publishBatch = async (productIds: number[]): Promise<IProductPublishResult[]> => {
|
|
101
|
+
try {
|
|
102
|
+
if (!productIds || productIds.length === 0) {
|
|
103
|
+
return [];
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
Logger.info(`Publishing batch of ${productIds.length} products: ${productIds.join(', ')}`);
|
|
107
|
+
const publications = await this.getPublications();
|
|
108
|
+
const publicationInputs = publications.map(p => ({ publicationId: p.id }));
|
|
109
|
+
|
|
110
|
+
// Build individual mutations for each product
|
|
111
|
+
const mutations = productIds.map((productId, index) => {
|
|
112
|
+
const gqlId = this.getGraphProductIdFromId(productId);
|
|
113
|
+
return `
|
|
114
|
+
publish${index}: productPublish(input: {
|
|
115
|
+
id: "${gqlId}",
|
|
116
|
+
productPublications: [${publicationInputs.map(p => `{publicationId: "${p.publicationId}"}`).join(', ')}]
|
|
117
|
+
}) {
|
|
118
|
+
product { id }
|
|
119
|
+
productPublications {
|
|
120
|
+
isPublished
|
|
121
|
+
channel { name }
|
|
122
|
+
}
|
|
123
|
+
userErrors { field message }
|
|
124
|
+
}
|
|
125
|
+
`;
|
|
126
|
+
}).join('\n');
|
|
127
|
+
|
|
128
|
+
const query = `mutation { ${mutations} }`;
|
|
129
|
+
const response = await this.axiosInstance.post('/graphql.json', { query }, { query_cost: productIds.length * 10 });
|
|
130
|
+
|
|
131
|
+
if (response && response.data && response.data.data) {
|
|
132
|
+
const results: IProductPublishResult[] = [];
|
|
133
|
+
for (let i = 0; i < productIds.length; i++) {
|
|
134
|
+
const key = `publish${i}`;
|
|
135
|
+
const publishResult = response.data.data[key];
|
|
136
|
+
if (publishResult?.product?.id) {
|
|
137
|
+
const productPublications = publishResult.productPublications || [];
|
|
138
|
+
results.push({
|
|
139
|
+
id: productIds[i],
|
|
140
|
+
productPublications: productPublications.filter((pp: any) => pp.isPublished).map((pp: any) => pp.channel)
|
|
141
|
+
});
|
|
142
|
+
} else if (publishResult?.userErrors?.length > 0) {
|
|
143
|
+
Logger.error(`Batch publish error for product ${productIds[i]}: ${JSON.stringify(publishResult.userErrors)}`);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return results;
|
|
147
|
+
} else {
|
|
148
|
+
throw new InspiraShopifyError({ message: JSON.stringify(response.data.errors) });
|
|
149
|
+
}
|
|
150
|
+
} catch (error) { this.logErrorAndThrow(error); }
|
|
151
|
+
};
|
|
152
|
+
|
|
93
153
|
/**
|
|
94
154
|
* Unpublishes product to all publication channels.
|
|
95
155
|
*
|