@haus-tech/product-import-export-plugin 2.2.0-dev.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.
Files changed (52) hide show
  1. package/dist/api/plugin.controller.d.ts +8 -0
  2. package/dist/api/plugin.controller.js +49 -0
  3. package/dist/api/product-export.controller.d.ts +14 -0
  4. package/dist/api/product-export.controller.js +117 -0
  5. package/dist/api/product-import.controller.d.ts +11 -0
  6. package/dist/api/product-import.controller.js +62 -0
  7. package/dist/constants.d.ts +2 -0
  8. package/dist/constants.js +5 -0
  9. package/dist/helpers/generate-asset-hash.d.ts +2 -0
  10. package/dist/helpers/generate-asset-hash.js +15 -0
  11. package/dist/helpers/normalize-string.d.ts +1 -0
  12. package/dist/helpers/normalize-string.js +16 -0
  13. package/dist/helpers/remove-update-at-fields.d.ts +5 -0
  14. package/dist/helpers/remove-update-at-fields.js +19 -0
  15. package/dist/index.d.ts +1 -0
  16. package/dist/index.js +17 -0
  17. package/dist/product-import-export.plugin.d.ts +13 -0
  18. package/dist/product-import-export.plugin.js +153 -0
  19. package/dist/providers/import-providers/asset-importer.d.ts +27 -0
  20. package/dist/providers/import-providers/asset-importer.js +127 -0
  21. package/dist/providers/import-providers/import-parser.d.ts +137 -0
  22. package/dist/providers/import-providers/import-parser.js +600 -0
  23. package/dist/providers/import-providers/product-importer.d.ts +47 -0
  24. package/dist/providers/import-providers/product-importer.js +729 -0
  25. package/dist/services/extended-fast-importer.service.d.ts +41 -0
  26. package/dist/services/extended-fast-importer.service.js +418 -0
  27. package/dist/services/product-export.service.d.ts +23 -0
  28. package/dist/services/product-export.service.js +340 -0
  29. package/dist/services/product-import.service.d.ts +21 -0
  30. package/dist/services/product-import.service.js +83 -0
  31. package/dist/types.d.ts +40 -0
  32. package/dist/types.js +2 -0
  33. package/dist/ui/components/export-dialog.component.d.ts +43 -0
  34. package/dist/ui/components/export-dialog.component.html +78 -0
  35. package/dist/ui/components/export-dialog.component.js +108 -0
  36. package/dist/ui/components/export-dialog.component.ts +142 -0
  37. package/dist/ui/components/product-import.component.d.ts +55 -0
  38. package/dist/ui/components/product-import.component.html +76 -0
  39. package/dist/ui/components/product-import.component.js +398 -0
  40. package/dist/ui/components/product-import.component.ts +528 -0
  41. package/dist/ui/product-export.service.d.ts +14 -0
  42. package/dist/ui/product-export.service.js +107 -0
  43. package/dist/ui/product-export.service.ts +107 -0
  44. package/dist/ui/providers.d.ts +2 -0
  45. package/dist/ui/providers.js +49 -0
  46. package/dist/ui/providers.ts +57 -0
  47. package/dist/ui/routes.d.ts +29 -0
  48. package/dist/ui/routes.js +12 -0
  49. package/dist/ui/routes.ts +11 -0
  50. package/dist/ui/translations/en.json +44 -0
  51. package/dist/ui/translations/sv.json +44 -0
  52. package/package.json +30 -0
@@ -0,0 +1,41 @@
1
+ import { Channel, ChannelService, ID, RequestContextService, StockMovementService, TransactionalConnection, TranslatableSaver } from '@vendure/core';
2
+ import { CreateFacetInput, CreateFacetValueInput, CreateProductInput, CreateProductOptionGroupInput, CreateProductOptionInput, CreateProductVariantInput } from '@vendure/common/lib/generated-types';
3
+ export declare class ExtendedFastImporterService {
4
+ private connection;
5
+ private channelService;
6
+ private stockMovementService;
7
+ private translatableSaver;
8
+ private requestContextService;
9
+ private defaultChannel;
10
+ private importCtx;
11
+ /** @internal */
12
+ constructor(connection: TransactionalConnection, channelService: ChannelService, stockMovementService: StockMovementService, translatableSaver: TranslatableSaver, requestContextService: RequestContextService);
13
+ /**
14
+ * @description
15
+ * This should be called prior to any of the import methods, as it establishes the
16
+ * default Channel as well as the context in which the new entities will be created.
17
+ *
18
+ * Passing a `channel` argument means that Products and ProductVariants will be assigned
19
+ * to that Channel.
20
+ */
21
+ initialize(channel?: Channel): Promise<void>;
22
+ updateProduct(id: ID, input: CreateProductInput & {
23
+ id: ID;
24
+ }): Promise<ID>;
25
+ createProduct(input: CreateProductInput): Promise<ID>;
26
+ updateProductOptionGroup(input: CreateProductOptionGroupInput & {
27
+ id: ID;
28
+ }): Promise<ID>;
29
+ createProductOptionGroup(input: CreateProductOptionGroupInput): Promise<ID>;
30
+ createProductOption(input: CreateProductOptionInput): Promise<ID>;
31
+ addOptionGroupToProduct(productId: ID, optionGroupId: ID): Promise<void>;
32
+ createFacet(input: CreateFacetInput): Promise<ID>;
33
+ createFacetValue(input: CreateFacetValueInput): Promise<ID>;
34
+ addFacetValueToProduct(productId: ID, facetValueId: ID): Promise<void>;
35
+ addFacetValueToProductVariant(variantId: ID, facetValueId: ID): Promise<void>;
36
+ updateProductVariant(input: CreateProductVariantInput & {
37
+ id: ID;
38
+ }): Promise<ID>;
39
+ createProductVariant(input: CreateProductVariantInput): Promise<ID>;
40
+ private ensureInitialized;
41
+ }
@@ -0,0 +1,418 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.ExtendedFastImporterService = void 0;
13
+ const common_1 = require("@nestjs/common");
14
+ const core_1 = require("@vendure/core");
15
+ const normalize_string_1 = require("../helpers/normalize-string");
16
+ const unique_1 = require("@vendure/common/lib/unique");
17
+ const lodash_1 = require("lodash");
18
+ let ExtendedFastImporterService = class ExtendedFastImporterService {
19
+ connection;
20
+ channelService;
21
+ stockMovementService;
22
+ translatableSaver;
23
+ requestContextService;
24
+ defaultChannel;
25
+ importCtx;
26
+ /** @internal */
27
+ constructor(connection, channelService, stockMovementService, translatableSaver, requestContextService) {
28
+ this.connection = connection;
29
+ this.channelService = channelService;
30
+ this.stockMovementService = stockMovementService;
31
+ this.translatableSaver = translatableSaver;
32
+ this.requestContextService = requestContextService;
33
+ }
34
+ /**
35
+ * @description
36
+ * This should be called prior to any of the import methods, as it establishes the
37
+ * default Channel as well as the context in which the new entities will be created.
38
+ *
39
+ * Passing a `channel` argument means that Products and ProductVariants will be assigned
40
+ * to that Channel.
41
+ */
42
+ async initialize(channel) {
43
+ this.importCtx = channel
44
+ ? await this.requestContextService.create({
45
+ apiType: 'admin',
46
+ channelOrToken: channel,
47
+ })
48
+ : core_1.RequestContext.empty();
49
+ this.defaultChannel = await this.channelService.getDefaultChannel(this.importCtx);
50
+ }
51
+ async updateProduct(id, input) {
52
+ this.ensureInitialized();
53
+ input.translations?.map((translation) => {
54
+ translation.slug = (0, normalize_string_1.normalizeString)(translation.slug, '-', translation.languageCode);
55
+ });
56
+ const product = await this.translatableSaver.update({
57
+ ctx: this.importCtx,
58
+ input,
59
+ entityType: core_1.Product,
60
+ translationType: core_1.ProductTranslation,
61
+ beforeSave: async (p) => {
62
+ p.channels = (0, unique_1.unique)([this.defaultChannel, this.importCtx.channel], 'id');
63
+ if (input.featuredAssetId) {
64
+ p.featuredAsset = { id: input.featuredAssetId };
65
+ }
66
+ },
67
+ });
68
+ if (input.assetIds) {
69
+ const existingAssets = await this.connection
70
+ .getRepository(this.importCtx, core_1.ProductAsset)
71
+ .find({
72
+ where: { productId: id },
73
+ });
74
+ const newAssets = input.assetIds
75
+ .filter((id) => !existingAssets.some((asset) => asset.assetId === id))
76
+ .map((id, i) => new core_1.ProductAsset({ assetId: id, productId: product.id, position: i }));
77
+ await this.connection
78
+ .getRepository(this.importCtx, core_1.ProductAsset)
79
+ .save(newAssets, { reload: false });
80
+ }
81
+ return product.id;
82
+ }
83
+ async createProduct(input) {
84
+ this.ensureInitialized();
85
+ // https://github.com/vendure-ecommerce/vendure/issues/2053
86
+ // normalizes slug without validation for faster performance
87
+ input.translations.map((translation) => {
88
+ translation.slug = (0, normalize_string_1.normalizeString)(translation.slug, '-', translation.languageCode);
89
+ });
90
+ const product = await this.translatableSaver.create({
91
+ ctx: this.importCtx,
92
+ input,
93
+ entityType: core_1.Product,
94
+ translationType: core_1.ProductTranslation,
95
+ beforeSave: async (p) => {
96
+ try {
97
+ p.channels = (0, unique_1.unique)([this.defaultChannel, this.importCtx.channel], 'id');
98
+ if (input.featuredAssetId) {
99
+ p.featuredAsset = { id: input.featuredAssetId };
100
+ }
101
+ }
102
+ catch (error) {
103
+ console.log(error);
104
+ }
105
+ },
106
+ });
107
+ if (input.assetIds) {
108
+ const productAssets = input.assetIds.map((id, i) => new core_1.ProductAsset({
109
+ assetId: id,
110
+ productId: product.id,
111
+ position: i,
112
+ }));
113
+ await this.connection
114
+ .getRepository(this.importCtx, core_1.ProductAsset)
115
+ .save(productAssets, { reload: false });
116
+ }
117
+ return product.id;
118
+ }
119
+ async updateProductOptionGroup(input) {
120
+ this.ensureInitialized();
121
+ const group = await this.translatableSaver.update({
122
+ ctx: this.importCtx,
123
+ input: { ...(0, lodash_1.omit)(input, 'options') },
124
+ entityType: core_1.ProductOptionGroup,
125
+ translationType: core_1.ProductOptionGroupTranslation,
126
+ });
127
+ return group.id;
128
+ }
129
+ async createProductOptionGroup(input) {
130
+ this.ensureInitialized();
131
+ const groupExists = await this.connection
132
+ .getRepository(this.importCtx, core_1.ProductOptionGroup)
133
+ .findOne({
134
+ where: { code: input.code },
135
+ });
136
+ if (groupExists) {
137
+ await this.translatableSaver.update({
138
+ ctx: this.importCtx,
139
+ input: { ...(0, lodash_1.omit)(input, 'options'), id: groupExists.id },
140
+ entityType: core_1.ProductOptionGroup,
141
+ translationType: core_1.ProductOptionGroupTranslation,
142
+ });
143
+ return groupExists.id;
144
+ }
145
+ const group = await this.translatableSaver.create({
146
+ ctx: this.importCtx,
147
+ input,
148
+ entityType: core_1.ProductOptionGroup,
149
+ translationType: core_1.ProductOptionGroupTranslation,
150
+ });
151
+ return group.id;
152
+ }
153
+ async createProductOption(input) {
154
+ this.ensureInitialized();
155
+ const optionsExist = await this.connection
156
+ .getRepository(this.importCtx, core_1.ProductOption)
157
+ .findOne({
158
+ where: { code: input.code, groupId: input.productOptionGroupId },
159
+ });
160
+ if (optionsExist) {
161
+ const updatedOption = await this.translatableSaver.update({
162
+ ctx: this.importCtx,
163
+ input: { ...input, id: optionsExist.id },
164
+ entityType: core_1.ProductOption,
165
+ translationType: core_1.ProductOptionTranslation,
166
+ beforeSave: (po) => (po.group = { id: input.productOptionGroupId }),
167
+ });
168
+ return updatedOption.id;
169
+ }
170
+ const option = await this.translatableSaver.create({
171
+ ctx: this.importCtx,
172
+ input,
173
+ entityType: core_1.ProductOption,
174
+ translationType: core_1.ProductOptionTranslation,
175
+ beforeSave: (po) => (po.group = { id: input.productOptionGroupId }),
176
+ });
177
+ return option.id;
178
+ }
179
+ async addOptionGroupToProduct(productId, optionGroupId) {
180
+ this.ensureInitialized();
181
+ await this.connection
182
+ .getRepository(this.importCtx, core_1.Product)
183
+ .createQueryBuilder()
184
+ .relation('optionGroups')
185
+ .of(productId)
186
+ .add(optionGroupId);
187
+ }
188
+ async createFacet(input) {
189
+ this.ensureInitialized();
190
+ const facetExists = await this.connection.getRepository(this.importCtx, core_1.Facet).findOne({
191
+ where: { code: input.code },
192
+ relations: ['channels', 'translations'],
193
+ });
194
+ if (facetExists) {
195
+ const facet = await this.translatableSaver.update({
196
+ ctx: this.importCtx,
197
+ input: { ...input, id: facetExists.id },
198
+ entityType: core_1.Facet,
199
+ translationType: core_1.FacetTranslation,
200
+ beforeSave: (facet) => {
201
+ facet.channels = (0, unique_1.unique)([this.defaultChannel, this.importCtx.channel], 'id');
202
+ },
203
+ });
204
+ return facet.id;
205
+ }
206
+ const facet = await this.translatableSaver.create({
207
+ ctx: this.importCtx,
208
+ input,
209
+ entityType: core_1.Facet,
210
+ translationType: core_1.FacetTranslation,
211
+ beforeSave: (facet) => {
212
+ facet.channels = (0, unique_1.unique)([this.defaultChannel, this.importCtx.channel], 'id');
213
+ },
214
+ });
215
+ return facet.id;
216
+ }
217
+ async createFacetValue(input) {
218
+ this.ensureInitialized();
219
+ const facetValueExists = await this.connection
220
+ .getRepository(this.importCtx, core_1.FacetValue)
221
+ .findOne({
222
+ where: { code: input.code },
223
+ relations: ['channels', 'translations'],
224
+ });
225
+ if (facetValueExists) {
226
+ const updatedFacetValue = await this.translatableSaver.update({
227
+ ctx: this.importCtx,
228
+ input: { ...input, id: facetValueExists.id },
229
+ entityType: core_1.FacetValue,
230
+ translationType: core_1.FacetValueTranslation,
231
+ beforeSave: (facetValue) => {
232
+ facetValue.facet = { id: input.facetId };
233
+ facetValue.channels = (0, unique_1.unique)([this.defaultChannel, this.importCtx.channel], 'id');
234
+ },
235
+ });
236
+ return updatedFacetValue.id;
237
+ }
238
+ const facetValue = await this.translatableSaver.create({
239
+ ctx: this.importCtx,
240
+ input,
241
+ entityType: core_1.FacetValue,
242
+ translationType: core_1.FacetValueTranslation,
243
+ beforeSave: (facetValue) => {
244
+ facetValue.facet = { id: input.facetId };
245
+ facetValue.channels = (0, unique_1.unique)([this.defaultChannel, this.importCtx.channel], 'id');
246
+ },
247
+ });
248
+ return facetValue.id;
249
+ }
250
+ async addFacetValueToProduct(productId, facetValueId) {
251
+ this.ensureInitialized();
252
+ const existingRelation = await this.connection
253
+ .getRepository(this.importCtx, core_1.Product)
254
+ .createQueryBuilder()
255
+ .relation(core_1.Product, 'facetValues')
256
+ .of(productId)
257
+ .loadMany();
258
+ if (!existingRelation.some((relation) => relation.id === facetValueId)) {
259
+ await this.connection
260
+ .getRepository(this.importCtx, core_1.Product)
261
+ .createQueryBuilder()
262
+ .relation(core_1.Product, 'facetValues')
263
+ .of(productId)
264
+ .add(facetValueId);
265
+ }
266
+ }
267
+ async addFacetValueToProductVariant(variantId, facetValueId) {
268
+ this.ensureInitialized();
269
+ const existingRelation = await this.connection
270
+ .getRepository(this.importCtx, core_1.ProductVariant)
271
+ .createQueryBuilder()
272
+ .relation(core_1.ProductVariant, 'facetValues')
273
+ .of(variantId)
274
+ .loadMany();
275
+ if (!existingRelation.some((relation) => relation.id === facetValueId)) {
276
+ await this.connection
277
+ .getRepository(this.importCtx, core_1.ProductVariant)
278
+ .createQueryBuilder()
279
+ .relation(core_1.ProductVariant, 'facetValues')
280
+ .of(variantId)
281
+ .add(facetValueId);
282
+ }
283
+ }
284
+ async updateProductVariant(input) {
285
+ this.ensureInitialized();
286
+ if (!input.optionIds) {
287
+ input.optionIds = [];
288
+ }
289
+ if (input.price == null) {
290
+ input.price = 0;
291
+ }
292
+ const inputWithoutPrice = {
293
+ ...input,
294
+ };
295
+ delete inputWithoutPrice.price;
296
+ const updatedVariant = await this.translatableSaver.update({
297
+ ctx: this.importCtx,
298
+ input: inputWithoutPrice,
299
+ entityType: core_1.ProductVariant,
300
+ translationType: core_1.ProductVariantTranslation,
301
+ beforeSave: async (variant) => {
302
+ variant.channels = (0, unique_1.unique)([this.defaultChannel, this.importCtx.channel], 'id');
303
+ const { optionIds } = input;
304
+ if (optionIds && optionIds.length) {
305
+ variant.options = optionIds.map((id) => ({ id }));
306
+ }
307
+ variant.product = { id: input.productId };
308
+ variant.taxCategory = { id: input.taxCategoryId };
309
+ if (input.featuredAssetId) {
310
+ variant.featuredAsset = { id: input.featuredAssetId };
311
+ }
312
+ },
313
+ });
314
+ if (input.assetIds) {
315
+ const existingAssets = await this.connection
316
+ .getRepository(this.importCtx, core_1.ProductVariantAsset)
317
+ .find({
318
+ where: { productVariantId: input.id },
319
+ });
320
+ const newAssets = input.assetIds
321
+ .filter((id) => !existingAssets.some((asset) => asset.assetId === id))
322
+ .map((id, i) => new core_1.ProductVariantAsset({
323
+ assetId: id,
324
+ productVariantId: updatedVariant.id,
325
+ position: i,
326
+ }));
327
+ await this.connection
328
+ .getRepository(this.importCtx, core_1.ProductVariantAsset)
329
+ .save(newAssets, { reload: false });
330
+ }
331
+ await this.stockMovementService.adjustProductVariantStock(this.importCtx, updatedVariant.id, input.stockOnHand ?? 0);
332
+ const assignedChannelIds = (0, unique_1.unique)([this.defaultChannel, this.importCtx.channel], 'id').map((c) => c.id);
333
+ for (const channelId of assignedChannelIds) {
334
+ const variantPrice = new core_1.ProductVariantPrice({
335
+ price: input.price,
336
+ channelId,
337
+ currencyCode: this.defaultChannel.defaultCurrencyCode,
338
+ });
339
+ variantPrice.variant = updatedVariant;
340
+ await this.connection
341
+ .getRepository(this.importCtx, core_1.ProductVariantPrice)
342
+ .update({ id: updatedVariant.id }, variantPrice);
343
+ }
344
+ return updatedVariant.id;
345
+ }
346
+ async createProductVariant(input) {
347
+ this.ensureInitialized();
348
+ if (!input.optionIds) {
349
+ input.optionIds = [];
350
+ }
351
+ if (input.price == null) {
352
+ input.price = 0;
353
+ }
354
+ const inputWithoutPrice = {
355
+ ...input,
356
+ };
357
+ delete inputWithoutPrice.price;
358
+ const createdVariant = await this.translatableSaver.create({
359
+ ctx: this.importCtx,
360
+ input: inputWithoutPrice,
361
+ entityType: core_1.ProductVariant,
362
+ translationType: core_1.ProductVariantTranslation,
363
+ beforeSave: async (variant) => {
364
+ variant.channels = (0, unique_1.unique)([this.defaultChannel, this.importCtx.channel], 'id');
365
+ const { optionIds } = input;
366
+ if (optionIds && optionIds.length) {
367
+ variant.options = optionIds.map((id) => ({ id }));
368
+ }
369
+ if (input.facetValueIds) {
370
+ variant.facetValues = input.facetValueIds.map((id) => ({ id }));
371
+ }
372
+ variant.product = { id: input.productId };
373
+ variant.taxCategory = { id: input.taxCategoryId };
374
+ if (input.featuredAssetId) {
375
+ variant.featuredAsset = { id: input.featuredAssetId };
376
+ }
377
+ },
378
+ });
379
+ if (input.assetIds) {
380
+ const variantAssets = input.assetIds.map((id, i) => new core_1.ProductVariantAsset({
381
+ assetId: id,
382
+ productVariantId: createdVariant.id,
383
+ position: i,
384
+ }));
385
+ await this.connection
386
+ .getRepository(this.importCtx, core_1.ProductVariantAsset)
387
+ .save(variantAssets, { reload: false });
388
+ }
389
+ await this.stockMovementService.adjustProductVariantStock(this.importCtx, createdVariant.id, input.stockOnHand ?? 0);
390
+ const assignedChannelIds = (0, unique_1.unique)([this.defaultChannel, this.importCtx.channel], 'id').map((c) => c.id);
391
+ for (const channelId of assignedChannelIds) {
392
+ const variantPrice = new core_1.ProductVariantPrice({
393
+ price: input.price,
394
+ channelId,
395
+ currencyCode: this.defaultChannel.defaultCurrencyCode,
396
+ });
397
+ variantPrice.variant = createdVariant;
398
+ await this.connection
399
+ .getRepository(this.importCtx, core_1.ProductVariantPrice)
400
+ .save(variantPrice, { reload: false });
401
+ }
402
+ return createdVariant.id;
403
+ }
404
+ ensureInitialized() {
405
+ if (!this.defaultChannel || !this.importCtx) {
406
+ throw new Error("The FastImporterService must be initialized with a call to 'initialize()' before importing data");
407
+ }
408
+ }
409
+ };
410
+ ExtendedFastImporterService = __decorate([
411
+ (0, common_1.Injectable)(),
412
+ __metadata("design:paramtypes", [core_1.TransactionalConnection,
413
+ core_1.ChannelService,
414
+ core_1.StockMovementService,
415
+ core_1.TranslatableSaver,
416
+ core_1.RequestContextService])
417
+ ], ExtendedFastImporterService);
418
+ exports.ExtendedFastImporterService = ExtendedFastImporterService;
@@ -0,0 +1,23 @@
1
+ import { EntityHydrator, ID, ProductService, RequestContext, StockLevelService, ChannelService, ConfigService } from '@vendure/core';
2
+ import { PluginInitOptions } from '../types';
3
+ export type RelationType = 'string' | 'boolean' | 'localeString' | 'text' | 'localeText' | 'int' | 'float' | 'datetime' | 'relation';
4
+ export declare class ProductExportService {
5
+ private options;
6
+ private productService;
7
+ private stockLevelService;
8
+ private entityHydratorService;
9
+ private channelService;
10
+ private configService;
11
+ constructor(options: PluginInitOptions, productService: ProductService, stockLevelService: StockLevelService, entityHydratorService: EntityHydrator, channelService: ChannelService, configService: ConfigService);
12
+ createExportFile(ctx: RequestContext, selectionIds: ID[], fileName: string, selectedCustomFields: string, exportAssetsAs: 'url' | 'json', selectedExportFields: string): Promise<string>;
13
+ private handleAssets;
14
+ private handleCustomFields;
15
+ private getStockOnHand;
16
+ private mapTranslations;
17
+ private mapFacetTranslations;
18
+ getCustomFields(ctx: RequestContext, productIds: string[]): Promise<{
19
+ name: string;
20
+ type: string;
21
+ }[]>;
22
+ getConfig(): Promise<PluginInitOptions>;
23
+ }