### Setup Vendure Product Feed Plugin Source: https://github.com/toonjanssens/vendure-product-feed-plugin/blob/main/README.md Example TypeScript configuration for integrating the ProductFeedPlugin into a Vendure application. It demonstrates how to add the plugin to the VendureConfig and its UI component, specifying necessary options like asset URL prefix and product URL generation. ```typescript import { ProductFeedPlugin, GoogleProductFeedStrategy } from "@codibri/vendure-product-feed-plugin"; import { AdminUiPlugin } from "@vendure/admin-ui-plugin"; import { compileUiExtensions } from "@vendure/ui-devkit"; import path from "path"; // ... plugins: [ AdminUiPlugin.init({ port: 3002, route: "admin", app: compileUiExtensions({ outputPath: path.join(__dirname, "../admin-ui"), extensions: [ProductFeedPlugin.ui], devMode: true, }), }), ProductFeedPlugin.init({ assetUrlPrefix: "https:///assets", productUrl: (shopUrl, variant) => `${shopUrl}/product/${variant.product.slug}`, folder: "custom-product-feed", feedStrategy: { getFileName: (channel) => `google-${channel.code}`, strategy: GoogleProductFeedStrategy, }, }), ]; ``` -------------------------------- ### Basic Vendure Product Feed Plugin Setup Source: https://context7.com/toonjanssens/vendure-product-feed-plugin/llms.txt Demonstrates the basic installation and configuration of the ProductFeedPlugin within a Vendure application. It includes setting up the asset URL prefix, product URL generation, folder for feeds, and defining the feed strategy, specifically using the GoogleProductFeedStrategy. ```typescript import { ProductFeedPlugin, GoogleProductFeedStrategy } from "@codibri/vendure-product-feed-plugin"; import { AdminUiPlugin } from "@vendure/admin-ui-plugin"; import { compileUiExtensions } from "@vendure/ui-devkit/compiler"; import path from "path"; const config: VendureConfig = { // ... other config plugins: [ AdminUiPlugin.init({ port: 3002, route: "admin", app: compileUiExtensions({ outputPath: path.join(__dirname, "../admin-ui"), extensions: [ProductFeedPlugin.ui], devMode: true, }), }), ProductFeedPlugin.init({ assetUrlPrefix: "https://my-vendure-shop.com/assets", productUrl: (shopUrl, variant) => `${shopUrl}/product/${variant.product.slug}`, folder: "product-feeds", feedStrategy: { getFileName: (channel) => `google-feed-${channel.code}`, strategy: GoogleProductFeedStrategy, }, }), ], }; ``` -------------------------------- ### Retrieve Product Feed via HTTP GET Request Source: https://context7.com/toonjanssens/vendure-product-feed-plugin/llms.txt Shows how to retrieve a product feed using a cURL command, demonstrating requests for the current channel and a specific channel using a token. It also includes an example of the expected XML response format. ```bash # Get feed for current channel curl https://my-vendure-shop.com/feed # Get feed for specific channel using token curl https://my-vendure-shop.com/feed?token=default-channel-token # Example response (XML) # # # # default-channel product catelog # https://my-shop.com # All products for default-channel # # SKU123 # Wireless Headphones # Premium wireless headphones with noise cancellation # https://my-shop.com/product/wireless-headphones # https://my-vendure-shop.com/assets/preview-url.jpg # 99.99 USD # in_stock # # # ``` -------------------------------- ### Install Vendure Product Feed Plugin Source: https://github.com/toonjanssens/vendure-product-feed-plugin/blob/main/README.md Instructions for installing the Vendure Product Feed plugin using either yarn or npm package managers. This is the first step before configuring the plugin. ```shell yarn add @codibri/vendure-product-feed-plugin ``` ```shell npm install @codibri/vendure-product-feed-plugin ``` -------------------------------- ### Automate Product Feed Builds with Cron Job Source: https://context7.com/toonjanssens/vendure-product-feed-plugin/llms.txt This section demonstrates how to automate product feed generation for all channels marked for rebuild. It uses the Vendure bootstrap function to get the ProductFeedBuilderService and then calls buildAllFeeds(). The provided bash command shows how to schedule this script to run nightly using crontab. ```typescript // scripts/rebuild-feeds.ts import { bootstrap } from "@vendure/core"; import { ProductFeedBuilderService } from "@codibri/vendure-product-feed-plugin"; import { config } from "./vendure-config"; async function buildFeeds() { const app = await bootstrap(config); const feedService = app.get(ProductFeedBuilderService); try { // Builds all channels where productFeedRebuild = true await feedService.buildAllFeeds(); console.log("Feed builds queued successfully"); } catch (error) { console.error("Feed build failed:", error); process.exit(1); } } buildFeeds(); ``` ```bash # Add to crontab for nightly builds # 0 2 * * * cd /app && node dist/scripts/rebuild-feeds.js ``` -------------------------------- ### REST API Endpoint Controller Implementation Source: https://context7.com/toonjanssens/vendure-product-feed-plugin/llms.txt Illustrates the TypeScript controller implementation for the `/feed` REST API endpoint in Vendure. This endpoint handles GET requests to retrieve product feeds, accepting an optional token for channel specification and returning either a 404 or the XML feed. ```typescript @Controller("feed") export class ProductController { @Get() async findAll( @Ctx() ctx: RequestContext, @Res() response: Response, @Query("token") token?: string ) { // Returns 404 if channel not configured for URL output // Returns XML feed with proper content-type header } } ``` -------------------------------- ### Implement Custom Product Feed Strategy Source: https://context7.com/toonjanssens/vendure-product-feed-plugin/llms.txt This code defines a custom feed strategy by extending the ProductFeedStrategy base class. It implements methods to get the file extension, create the feed structure, add individual products, and end the feed generation. This allows for defining custom XML formats for product feeds. ```typescript // strategies/custom-feed-strategy.ts import { ProductFeedStrategy, Extra } from "@codibri/vendure-product-feed-plugin"; import { ProductVariant, AvailableStock } from "@vendure/core"; import { Writable } from "stream"; import { createCB } from "xmlbuilder2"; import { XMLBuilderCB } from "xmlbuilder2/lib/interfaces"; export class CustomFeedStrategy implements ProductFeedStrategy { private xml: XMLBuilderCB; getExtention(): string { return "xml"; } create(file: Writable, { channel }: Extra): void { this.xml = createCB({ data: (text: string) => file.write(text), prettyPrint: true, }); this.xml.on("end", () => file.end()); const root = this.xml.dec({ version: "1.0" }); const feed = root.ele("products"); feed.att("channel", channel.code); feed.att("generated", new Date().toISOString()); this.xml = feed; } addProduct(variant: ProductVariant, stock: AvailableStock, { channel, options }: Extra): void { const product = this.xml.ele("product"); product.ele("id").txt(variant.sku).up(); product.ele("name").txt(variant.name).up(); product.ele("price").txt((variant.priceWithTax / 100).toString()).up(); product.ele("currency").txt(variant.currencyCode).up(); const inStock = variant.trackInventory === "TRUE" ? stock.stockOnHand > 0 : true; product.ele("available").txt(inStock.toString()).up(); const url = options.productUrl( channel.customFields.productFeedShopUrl || "", variant ); product.ele("url").txt(url).up(); product.up(); } end(): void { this.xml.end(); } } ``` -------------------------------- ### GET /feed Source: https://context7.com/toonjanssens/vendure-product-feed-plugin/llms.txt Retrieves the product feed for the current or a specified channel via an HTTP GET request. The feed is generated in XML format. ```APIDOC ## GET /feed ### Description Retrieves the product feed for the current or a specified channel via an HTTP GET request. The feed is generated in XML format. ### Method GET ### Endpoint /feed ### Parameters #### Query Parameters - **token** (string) - Optional - A token to specify a particular channel for which to retrieve the feed. If not provided, the feed for the current channel is returned. ### Request Example ```bash # Get feed for current channel curl https://my-vendure-shop.com/feed # Get feed for specific channel using token curl https://my-vendure-shop.com/feed?token=default-channel-token ``` ### Response #### Success Response (200) - The response will be an XML document containing the product catalog. The structure will adhere to the Google Product Feed specification. #### Response Example ```xml default-channel product catelog https://my-shop.com All products for default-channel SKU123 Wireless Headphones Premium wireless headphones with noise cancellation https://my-shop.com/product/wireless-headphones https://my-vendure-shop.com/assets/preview-url.jpg 99.99 USD in_stock ``` ``` -------------------------------- ### Automatically Build All Product Feeds (TypeScript) Source: https://github.com/toonjanssens/vendure-product-feed-plugin/blob/main/README.md This script, written in TypeScript, demonstrates how to programmatically trigger the rebuilding of all product catalog feeds for Vendure. It utilizes the Vendure core bootstrap functionality and the ProductCatalogFeedService from the specified plugin. Ensure that Vendure configuration and the plugin are correctly set up before running. ```typescript // product-catalog-feed.ts import { bootstrap } from "@vendure/core"; import { ProductCatalogFeedService } from "@codibri/vendure-plugin-product-catalog-feed"; import { config } from "./vendure-config"; bootstrap(config) .then((app) => app.get(ProductCatalogFeedService).buildAllFeeds()) .catch((err) => { console.log(err); }); ``` -------------------------------- ### Vendure SFTP Upload Job Processor (JavaScript) Source: https://context7.com/toonjanssens/vendure-product-feed-plugin/llms.txt Handles the SFTP upload job, establishing a connection using credentials stored in channel custom fields, and transferring the generated feed file. ```javascript const job = { name: "product-feed-upload", process: async (job) => { const sftp = new Client(); await sftp.connect({ host: channel.customFields.productFeedSftpServer, port: channel.customFields.productFeedSftpPort, username: channel.customFields.productFeedSftpUser, password: channel.customFields.productFeedSftpPassword, }); await sftp.delete(fileName, true); // Remove old file await sftp.put(fileBuffer, fileName); // Upload new file await sftp.end(); return { success: true, file: fileName }; } }; ``` -------------------------------- ### Vendure SFTP Upload Service Configuration (TypeScript) Source: https://context7.com/toonjanssens/vendure-product-feed-plugin/llms.txt Configures the service for automatic SFTP uploads after feed generation. This service queues upload jobs using channel-specific SFTP credentials. ```typescript // Triggered automatically via ProductFeedUpdatedEvent @Injectable() export class ProductFeedUploadService { async uploadToSftp(channel: Channel, filePath: string, fileName: string) { // Queues upload job with channel SFTP credentials return this.jobQueue.add({ channelId: channel.id, filePath, fileName }); } } ``` -------------------------------- ### Vendure Event-Driven Feed Rebuild (TypeScript) Source: https://context7.com/toonjanssens/vendure-product-feed-plugin/llms.txt Subscribes to Vendure product and product variant events to automatically mark channels for feed rebuilds. Also handles SFTP uploads upon feed updates. ```typescript export class ProductFeedPlugin { async onApplicationBootstrap() { // Mark channel when any product is updated this.eventBus.ofType(ProductEvent).subscribe(async (event) => { return this.productFeedBuilderService.markChannelForRebuild(event.ctx); }); // Mark channel when any variant is updated this.eventBus.ofType(ProductVariantEvent).subscribe((event) => { return this.productFeedBuilderService.markChannelForRebuild(event.ctx); }); // Upload to SFTP when feed is rebuilt this.eventBus.ofType(ProductFeedUpdatedEvent).subscribe((event) => { if (event.ctx.channel.customFields.productFeedOutput === 'sftp') { return this.productFeedUploadService.uploadToSftp( event.ctx.channel, event.filePath, event.fileName ); } }); } } ``` -------------------------------- ### Configure Custom Feed Strategy in Plugin Source: https://context7.com/toonjanssens/vendure-product-feed-plugin/llms.txt This snippet shows how to configure the ProductFeedPlugin to use a custom feed strategy. It involves initializing the plugin with options such as asset URL prefix, a product URL generator, and specifying the custom feed strategy and its filename generation logic. ```typescript ProductFeedPlugin.init({ assetUrlPrefix: "https://my-vendure-shop.com/assets", productUrl: (shopUrl, variant) => `${shopUrl}/p/${variant.sku}`, feedStrategy: { getFileName: (channel) => `custom-feed-${channel.code}`, strategy: CustomFeedStrategy, }, }); ``` -------------------------------- ### Vendure Product Feed Plugin Type Definitions (TypeScript) Source: https://context7.com/toonjanssens/vendure-product-feed-plugin/llms.txt Defines core interfaces and types for configuring the Vendure Product Feed Plugin. Includes options for asset URLs, product URLs, and strategy implementations. ```typescript import { ProductVariant, Channel, AvailableStock } from "@vendure/core"; import { Writable } from "stream"; export type ProductFeedStrategyOptions = { assetUrlPrefix: string; productUrl: (shopUrl: string, variant: ProductVariant) => string; } export type Extra = { channel: Channel; options: ProductFeedStrategyOptions; } export abstract class ProductFeedStrategy { abstract getExtention(): string; abstract create(file: Writable, extra: Extra): void; abstract addProduct(variant: ProductVariant, stock: AvailableStock, extra: Extra): void; abstract end(extra: Extra): void; } type FeedStrategy = { getFileName: (channel: Channel) => string; strategy: new() => ProductFeedStrategy; } export interface ProductFeedPluginOptions extends ProductFeedStrategyOptions { feedStrategy: FeedStrategy; folder?: string; // Default: "product-feed" } ``` -------------------------------- ### Trigger Manual Product Feed Rebuild via GraphQL Source: https://context7.com/toonjanssens/vendure-product-feed-plugin/llms.txt This snippet shows how to trigger a manual product feed rebuild using a GraphQL mutation. It requires the 'graphql-request' library and an authorization token. The mutation returns the job ID, state, and progress of the rebuild process. ```graphql mutation RebuildProductFeed { rebuildProduct { id state progress } } ``` ```typescript import { AdminUiPlugin } from "@vendure/admin-ui-plugin"; import { gql, GraphQLClient } from "graphql-request"; const client = new GraphQLClient("https://my-vendure-shop.com/admin-api", { headers: { "Authorization": "Bearer admin-token", "vendure-token": "default-channel-token" } }); async function triggerRebuild() { const mutation = gql` mutation RebuildProductFeed { rebuildProduct { id state progress result } } `; try { const data = await client.request(mutation); console.log("Job queued:", data.rebuildProduct); } catch (error) { console.error("Failed to trigger rebuild:", error); } } // Requires ProductFeedRebuild permission ``` -------------------------------- ### Channel Custom Fields for Product Feed Configuration Source: https://context7.com/toonjanssens/vendure-product-feed-plugin/llms.txt Defines the TypeScript interface for custom fields added to Vendure channels to configure product feed generation. These fields control feed rebuilding, SFTP details, and the output mode (disabled, URL, or SFTP). ```typescript interface CustomChannelFields { productFeedRebuild: boolean; // Internal flag for rebuild tracking productFeedFile?: string; // Stored feed file path productFeedShopUrl?: string; // Shop frontend URL productFeedOutput: 'disabled' | 'url' | 'sftp'; productFeedSftpServer?: string; // SFTP hostname productFeedSftpPort?: number; // SFTP port (1-65535, default 22) productFeedSftpUser?: string; // SFTP username productFeedSftpPassword?: string; // SFTP password (encrypted) } ``` -------------------------------- ### Vendure Channel Rebuild Marking Implementation (TypeScript) Source: https://context7.com/toonjanssens/vendure-product-feed-plugin/llms.txt Implements the logic to mark a Vendure channel for feed rebuild. It checks if the channel feed output is enabled and updates the channel custom fields accordingly. ```typescript async markChannelForRebuild(ctx: RequestContext) { const channel = ctx.channel; if (channel.customFields.productFeedOutput === "disabled") { return; // Skip disabled channels } if (!channel.customFields.productFeedRebuild) { channel.customFields.productFeedRebuild = true; await this.connection.getRepository(ctx, Channel).save(channel); } } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.