### Quick Start Option Selection Source: https://docs.vendure.io/current/core/getting-started/installation When using @vendure/create, select 'Quick Start' for an automated setup. This option handles all configuration and database setup. ```console ┌ Let's create a Vendure App ✨ │ ◆ How should we proceed? │ ● Quick Start (Get up and running in a single step) # [!code highlight] │ ○ Manual Configuration └ ``` -------------------------------- ### Start MinIO Server (Direct Installation) Source: https://docs.vendure.io/current/core/how-to/s3-asset-storage If not using Docker, download and install MinIO, then start the server with this command, specifying the data directory and console address. ```bash minio server /data --console-address ":9001" ``` -------------------------------- ### Implementing the init Hook Source: https://docs.vendure.io/current/core/reference/typescript-api/common/injectable-strategy Example of how to implement the init hook to perform setup logic using the provided Injector. ```typescript async init(injector: Injector) { const myService = injector.get(MyService); await myService.doSomething(); } ``` -------------------------------- ### Verbose Installation Logging Source: https://docs.vendure.io/current/core/getting-started/installation To get more detailed output during installation and troubleshoot issues, use the --log-level verbose flag with the create command. ```bash npx @vendure/create my-shop --log-level verbose ``` -------------------------------- ### Configure OpenTelemetry Node SDK Source: https://docs.vendure.io/current/core/reference/core-plugins/telemetry-plugin/get-sdk-configuration Example demonstrating how to configure and start the OpenTelemetry Node SDK using `getSdkConfiguration`. This setup includes custom trace and log exporters and processors. Ensure environment variables like OTEL_EXPORTER_OTLP_ENDPOINT are set. ```typescript import { OTLPLogExporter, } from '@opentelemetry/exporter-logs-otlp-proto'; import { OTLPTraceExporter, } from '@opentelemetry/exporter-trace-otlp-http'; import { BatchLogRecordProcessor, } from '@opentelemetry/sdk-logs'; import { NodeSDK } from '@opentelemetry/sdk-node'; import { BatchSpanProcessor, } from '@opentelemetry/sdk-trace-base'; import { getSdkConfiguration, } from '@vendure/telemetry-plugin/preload'; process.env.OTEL_EXPORTER_OTLP_ENDPOINT = 'http://localhost:3100/otlp'; process.env.OTEL_LOGS_EXPORTER = 'otlp'; process.env.OTEL_RESOURCE_ATTRIBUTES = 'service.name=vendure-dev-server'; const traceExporter = new OTLPTraceExporter({ url: 'http://localhost:4318/v1/traces', }); const logExporter = new OTLPLogExporter(); const config = getSdkConfiguration({ config: { spanProcessors: [new BatchSpanProcessor(traceExporter)], logRecordProcessors: [new BatchLogRecordProcessor(logExporter)], }, }); const sdk = new NodeSDK(config); sdk.start(); ``` -------------------------------- ### Install MinIO Server with Docker Compose Source: https://docs.vendure.io/current/core/how-to/s3-asset-storage Use this command to start the MinIO server using Docker Compose. Ensure you have a docker-compose.yml file configured for MinIO. ```bash docker compose up -d minio ``` -------------------------------- ### Example Deployment Script for Vendure Source: https://docs.vendure.io/current/core/extending-the-dashboard/deployment A sample `package.json` script demonstrating how to build the Vendure server and dashboard separately, and then start the production server. Ensure the build steps align with your deployment pipeline. ```json { "scripts": { "build": "npm run build:server && npm run build:dashboard", "build:server": "tsc", "build:dashboard": "vite build", "start:prod": "node ./dist/index.js" } } ``` -------------------------------- ### SettingsStoreService Usage Example Source: https://docs.vendure.io/current/core/reference/typescript-api/services/settings-store-service Demonstrates how to get and set individual settings, as well as retrieve multiple settings using the SettingsStoreService. ```typescript import { RequestContext } from '@vendure/core'; // Assuming this.settingsStoreService is available in the current service context // Get a specific setting const userTheme = await this.settingsStoreService.get('dashboard.theme', ctx); // Set a specific setting await this.settingsStoreService.set('dashboard.theme', 'dark', ctx); // Get multiple settings const settings = await this.settingsStoreService.getMany([ 'dashboard.theme', 'dashboard.tableFilters' ], ctx); ``` -------------------------------- ### Run Sanity Studio Locally Source: https://docs.vendure.io/current/core/how-to/cms-integration-plugin Start the Sanity Studio development server to preview your CMS setup. ```bash npm run dev ``` -------------------------------- ### Bootstrap JobQueueService Source: https://docs.vendure.io/current/core/reference/typescript-api/job-queue/in-memory-job-queue-strategy This example shows how to bootstrap the Vendure application and start the JobQueueService, which is necessary for the InMemoryJobQueueStrategy to function. ```typescript bootstrap(config) .then(app => app.get(JobQueueService).start()); ``` -------------------------------- ### Vendure Server Build and Start Commands Source: https://docs.vendure.io/current/core/deployment/deploy-to-render Use these commands when configuring a Node.js runtime for your Vendure server on Render if not using a Dockerfile. The build command installs dependencies and builds the project, while the start command runs the server. ```bash yarn; yarn build ``` ```bash node ./dist/index.js ``` -------------------------------- ### Install Loyalty Points Plugin Source: https://docs.vendure.io/current/core/how-to/publish-plugin Install the loyalty points plugin using npm. ```bash npm install @acme/vendure-plugin-loyalty-points ``` -------------------------------- ### Install MinIO Client (mc) on Linux Source: https://docs.vendure.io/current/core/how-to/s3-asset-storage Installs the MinIO Client (mc) on Linux by downloading the binary and adding it to the PATH. ```bash # Linux curl https://dl.min.io/client/mc/release/linux-amd64/mc \ --create-dirs -o $HOME/minio-binaries/mc chmod +x $HOME/minio-binaries/mc export PATH=$PATH:$HOME/minio-binaries/ ``` -------------------------------- ### Install BullMQ Package Source: https://docs.vendure.io/current/core/reference/core-plugins/job-queue-plugin/bull-mqjob-queue-strategy To use this strategy, you need to manually install the `bullmq` package. ```shell npm install bullmq@^5.4.2 ``` -------------------------------- ### Start Server with Instrumentation Source: https://docs.vendure.io/current/core/reference/core-plugins/telemetry-plugin Start the Vendure server using the `--require` flag to load the instrumentation script. ```bash node --require ./dist/instrumentation.js ./dist/server.js ``` ```bash npx ts-node --require ./src/instrumentation.ts ./src/server.ts ``` -------------------------------- ### Install Pub/Sub Client Source: https://docs.vendure.io/current/community-plugins/pub-sub-plugin/pub-sub-job-queue-strategy Install the Google Cloud Pub/Sub client library required for the PubSubJobQueueStrategy. ```bash npm install @google-cloud/pubsub@^4.11.0 ``` -------------------------------- ### Run Plugin Migration and Start Server Source: https://docs.vendure.io/current/core/developer-guide/plugins Applies generated migration changes to the database and starts the Vendure development server. ```bash npx vendure migrate wishlist-plugin npm run dev ``` -------------------------------- ### Install Google Auth Library Source: https://docs.vendure.io/current/core/how-to/google-oauth-authentication Install the Google Auth Library to securely verify ID tokens on the server side. ```bash npm install google-auth-library ``` -------------------------------- ### Install Mollie Plugin and Client Source: https://docs.vendure.io/current/community-plugins/mollie-plugin Install the Mollie plugin and the Mollie API client using npm, pnpm, yarn, or bun. ```bash npm install @vendure-community/mollie-plugin @mollie/api-client ``` -------------------------------- ### Install Copyfiles with Yarn Source: https://docs.vendure.io/current/core/legacy-apis/extending-the-admin-ui/getting-started Command to install the `copyfiles` package using yarn. ```bash yarn add copyfiles ``` -------------------------------- ### Install Asset Server Plugin Source: https://docs.vendure.io/current/core/reference/core-plugins/asset-server-plugin Install the Asset Server Plugin using yarn or npm. ```bash yarn add @vendure/asset-server-plugin ``` ```bash npm install @vendure/asset-server-plugin ``` -------------------------------- ### Custom TestDbInitializer Example Source: https://docs.vendure.io/current/core/reference/typescript-api/testing/test-db-initializer Implement the TestDbInitializer interface to create custom database setup logic for specific database types. Register your custom initializer using the registerInitializer function. ```typescript export class CockroachDbInitializer implements TestDbInitializer { // database-specific implementation goes here } registerInitializer('cockroachdb', new CockroachDbInitializer()); ``` -------------------------------- ### Install Copyfiles with NPM Source: https://docs.vendure.io/current/core/legacy-apis/extending-the-admin-ui/getting-started Command to install the `copyfiles` package using npm. ```bash npm install copyfiles ``` -------------------------------- ### Install Stripe Plugin and Node Library Source: https://docs.vendure.io/current/community-plugins/stripe-plugin Install the Stripe community plugin and the Stripe Node.js library using npm, pnpm, yarn, or bun. ```bash npm install @vendure-community/stripe-plugin stripe ``` -------------------------------- ### Installing HardenPlugin Source: https://docs.vendure.io/current/core/deployment/production-configuration Installs the HardenPlugin to secure your Vendure API against malicious queries and schema manipulation. Use npm or yarn for installation. ```bash npm install @vendure/harden-plugin # or yarn add @vendure/harden-plugin ``` -------------------------------- ### Install @vendure/ui-devkit with npm Source: https://docs.vendure.io/current/core/legacy-apis/extending-the-admin-ui/getting-started Install the `@vendure/ui-devkit` package as a development dependency using npm. ```bash npm install --save-dev @vendure/ui-devkit ``` -------------------------------- ### Install node-fetch Source: https://docs.vendure.io/current/core/core-concepts/auth Install the `node-fetch` library, which is used in the backend strategy to make HTTP calls to the Keycloak server for token validation. ```bash npm install node-fetch ``` -------------------------------- ### Install @vendure/ui-devkit with yarn Source: https://docs.vendure.io/current/core/legacy-apis/extending-the-admin-ui/getting-started Install the `@vendure/ui-devkit` package as a development dependency using yarn. ```bash yarn add --dev @vendure/ui-devkit ``` -------------------------------- ### Install @vendure/ui-devkit Source: https://docs.vendure.io/current/core/legacy-apis/extending-the-admin-ui/using-other-frameworks Install the necessary package for creating UI extensions. This package includes the compiler and Angular dependencies. ```bash yarn add @vendure/ui-devkit # or npm install @vendure/ui-devkit ``` -------------------------------- ### Install Vendure UI Devkit Source: https://docs.vendure.io/current/core/how-to/publish-plugin If your plugin includes UI extensions, install the @vendure/ui-devkit package. ```bash npm install @vendure/ui-devkit ``` -------------------------------- ### Install PunchOutGatewayPlugin Source: https://docs.vendure.io/current/community-plugins/punch-out-gateway-plugin Install the plugin using npm. Other package managers like pnpm, yarn, or bun can also be used. ```bash npm install @vendure-community/punchout-gateway-plugin ``` -------------------------------- ### Install Stripe.js for Storefront Source: https://docs.vendure.io/current/community-plugins/stripe-plugin Install the Stripe.js library for your storefront project to handle payment UI and confirmation. This is required for the custom payment flow. ```bash npm install @stripe/stripe-js ``` -------------------------------- ### Populate Vendure Server with Initial Data and Products Source: https://docs.vendure.io/current/core/reference/typescript-api/import-export/populate This example demonstrates how to use the populate function to bootstrap the Vendure server, provide initial data, and import products from a CSV file. Ensure the necessary imports and configuration are in place. ```typescript import { bootstrap } from '@vendure/core'; import { populate } from '@vendure/core/cli'; import { config } from './vendure-config.ts' import { initialData } from './my-initial-data.ts'; const productsCsvFile = path.join(__dirname, 'path/to/products.csv') populate( () => bootstrap(config), initialData, productsCsvFile, ) .then(app => app.close()) .then( () => process.exit(0), err => { console.log(err); process.exit(1); }, ); ``` -------------------------------- ### Start Vendure Project and Development Server Source: https://docs.vendure.io/current/core/getting-started/installation After project creation, navigate to the project directory and run the development command to start both the backend server and the frontend storefront. ```bash cd my-shop npm run dev ``` -------------------------------- ### Get Buffer Sizes Example Source: https://docs.vendure.io/current/core/reference/typescript-api/job-queue/job-buffer-storage-strategy Demonstrates how to retrieve the number of buffered jobs for specific buffer IDs. Pass an empty array to get sizes for all buffers. ```typescript const sizes = await myJobBufferStrategy.bufferSize(['buffer-1', 'buffer-2']); // sizes = { 'buffer-1': 12, 'buffer-2': 3 } ``` -------------------------------- ### Basic useQuery Example Source: https://docs.vendure.io/current/core/reference/admin-ui-api/react-hooks/use-query Demonstrates how to use the useQuery hook to fetch product data. Includes handling for loading and error states. Requires the 'graphql-tag' package for gql. ```typescript import { useQuery } from '@vendure/admin-ui/react'; import { gql } from 'graphql-tag'; const GET_PRODUCT = gql` query GetProduct($id: ID!) { product(id: $id) { id name description } }`; export const MyComponent = () => { const { data, loading, error } = useQuery(GET_PRODUCT, { id: '1' }, { refetchOnChannelChange: true }); if (loading) return
Loading...
; if (error) return
Error! { error }
; return (

{data.product.name}

{data.product.description}

); }; ``` -------------------------------- ### Health Check Request Source: https://docs.vendure.io/current/core/deployment/using-docker Example HTTP GET request to the server's health check endpoint. ```text REQUEST: GET http://localhost:3000/health ``` -------------------------------- ### Populate Vendure with Test Data Source: https://docs.vendure.io/current/core/developer-guide/importing-data This script populates an existing Vendure installation with test data, similar to the initial setup. It utilizes assets from the `@vendure/create` package and ensures database synchronization. Ensure you have `@vendure/create` installed as a dev dependency. ```typescript import { populate } from '@vendure/core/cli'; import { bootstrap, VendureConfig } from '@vendure/core'; import { config } from './vendure-config'; populate( () => bootstrap({ ...config, importExportOptions: { importAssetsDir: path.join( require.resolve('@vendure/create/assets/products.csv'), '../images' ), }, dbConnectionOptions: {...config.dbConnectionOptions, synchronize: true} }), require('@vendure/create/assets/initial-data.json'), require.resolve('@vendure/create/assets/products.csv') ) .then(app => app.close()) .catch(err => { console.log(err); process.exit(1); }); ``` -------------------------------- ### Dashboard TSConfig Setup - Compiler Options Source: https://docs.vendure.io/current/core/extending-the-dashboard/migration Example `tsconfig.dashboard.json` configuration for enabling JSX support in dashboard extensions. This should extend the base `tsconfig.json`. ```json { "extends": "./tsconfig.json", "compilerOptions": { "composite": true, "jsx": "react-jsx" }, "include": [ "src/dashboard/**/*.ts", "src/dashboard/**/*.tsx" ] } ``` -------------------------------- ### Get Buffered Job Sizes Source: https://docs.vendure.io/current/core/reference/typescript-api/job-queue/job-queue-service Example of how to retrieve the number of jobs currently buffered for specific job buffers. This can help determine if flushing is necessary. ```typescript const sizes = await this.jobQueueService.bufferSize('buffer-1', 'buffer-2'); // sizes = { 'buffer-1': 12, 'buffer-2': 3 } ``` -------------------------------- ### Basic Usage of createTestEnvironment Source: https://docs.vendure.io/current/core/reference/typescript-api/testing/create-test-environment Demonstrates how to set up and initialize the test environment for end-to-end tests. Ensure to call server.init() and server.destroy() appropriately. ```typescript import { createTestEnvironment, testConfig } from '@vendure/testing'; describe('some feature to test', () => { const { server, adminClient, shopClient } = createTestEnvironment(testConfig); beforeAll(async () => { await server.init({ // ... server options }); await adminClient.asSuperAdmin(); }); afterAll(async () => { await server.destroy(); }); // ... end-to-end tests here }); ``` -------------------------------- ### Using usePaginatedList in a Component Source: https://docs.vendure.io/current/core/reference/dashboard/hooks/use-paginated-list This example shows how to use the usePaginatedList hook to get the refetch function and call it after a successful mutation to refresh the paginated list data. ```typescript const { refetchPaginatedList } = usePaginatedList(); const mutation = useMutation({ mutationFn: api.mutate(updateFacetValueDocument), onSuccess: () => { refetchPaginatedList(); }, }); ``` -------------------------------- ### Bootstrap Vendure Worker Source: https://docs.vendure.io/current/core/reference/typescript-api/worker/bootstrap-worker This example demonstrates how to bootstrap a Vendure worker using the bootstrapWorker function. It starts the job queue after successful initialization and handles potential errors. ```typescript import { bootstrapWorker } from '@vendure/core'; import { config } from './vendure-config'; bootstrapWorker(config) .then(worker => worker.startJobQueue()) .catch(err => { console.log(err); process.exit(1); }); ``` -------------------------------- ### Synchronous Custom Field Validation Source: https://docs.vendure.io/current/core/developer-guide/custom-fields Example of a synchronous validation function for a string custom field. It checks if a URL starts with 'http' and returns localized error messages if invalid. ```typescript import { LanguageCode, LocalizedString, } from '@vendure/core'; const config = { // ... customFields: { Product: [ { name: 'infoUrl', type: 'string', validate: (value: any) => { if (!value.startsWith('http')) { // If a localized error message is not required, a simple string can be returned. // return 'The URL must start with "http"'; // If a localized error message is required, return an array of LocalizedString objects. return [ { languageCode: LanguageCode.en, value: 'The URL must start with "http"' }, { languageCode: LanguageCode.de, value: 'Die URL muss mit "http" beginnen' }, { languageCode: LanguageCode.es, value: 'La URL debe comenzar con "http"' }, ]; } }, }, ] } }; ``` -------------------------------- ### Complete Dashboard Navigation Example Source: https://docs.vendure.io/current/core/extending-the-dashboard/navigation This comprehensive example demonstrates creating custom navigation sections ('Content', 'Media') and defining routes within them. It also shows how to add a menu item to an existing section ('Settings') and how to use `order` and `placement` properties for precise navigation control. ```tsx import { defineDashboardExtension } from '@vendure/dashboard'; import { FileTextIcon, ImageIcon, TagIcon, FolderIcon, SettingsIcon } from 'lucide-react'; defineDashboardExtension({ // Create custom navigation sections navSections: [ { id: 'content', title: 'Content', icon: FileTextIcon, placement: 'top', // Platform area order: 250, // Between Catalog (200) and Sales (300) }, { id: 'media', title: 'Media', icon: ImageIcon, placement: 'top', // Platform area order: 275, // After Content section }, ], routes: [ // Content section items { path: '/articles', component: () =>
Articles List
, navMenuItem: { sectionId: 'content', id: 'articles', title: 'Articles', }, }, { path: '/pages', component: () =>
Pages List
, navMenuItem: { sectionId: 'content', id: 'pages', title: 'Pages', }, }, { path: '/categories', component: () =>
Categories List
, navMenuItem: { sectionId: 'content', id: 'categories', title: 'Categories', }, }, // Media section items { path: '/media-library', component: () =>
Media Library
, navMenuItem: { sectionId: 'media', id: 'media-library', title: 'Library', }, }, { path: '/media-folders', component: () =>
Media Folders
, navMenuItem: { sectionId: 'media', id: 'media-folders', title: 'Folders', }, }, // Add to existing settings section { path: '/cms-settings', component: () =>
CMS Settings
, navMenuItem: { sectionId: 'settings', id: 'cms-settings', title: 'CMS Settings', }, }, ], }); ``` -------------------------------- ### Create and Use Cache Instance Source: https://docs.vendure.io/current/core/reference/typescript-api/cache Demonstrates how to create a cache instance with custom key generation and options, and then use it to retrieve data, fetching from the source if not found in the cache. ```typescript const cache = cacheService.createCache({ getKey: id => `ProductVariantIds:${id}`, options: { ttl: 1000 * 60 * 60, tags: ['products'], }, }); // This will fetch the value from the cache if it exists, or // fetch it from the ProductService if not, and then cache // using the key 'ProductVariantIds.${id}'. const variantIds = await cache.get(id, async () => { const variants await ProductService.getVariantsByProductId(ctx, id) ; // The cached value must be serializable, so we just return the ids return variants.map(v => v.id); }); ``` -------------------------------- ### Get Active Order Query Source: https://docs.vendure.io/current/core/storefront/active-order Retrieves the current active order using the `activeOrder` query and the predefined `ActiveOrder` fragment. This is the starting point for viewing or modifying the customer's cart. ```graphql query GetActiveOrder { activeOrder { ...ActiveOrder } } ``` ```graphql query GetActiveOrder { activeOrder { ...ActiveOrder } } ``` -------------------------------- ### Dashboard TSConfig Setup - Path Mapping Source: https://docs.vendure.io/current/core/extending-the-dashboard/migration Example `paths` configuration in `tsconfig.json` for resolving internal Vendure Dashboard imports and GraphQL types. Adjust paths based on project structure. ```json "paths": { // Import alias for the GraphQL types, this needs to point to // the location specified in the vite.config.mts file as `gqlOutputPath` // so will vary depending on project structure "@/gql": ["./apps/server/src/gql/graphql.ts"], // This line allows TypeScript to properly resolve internal // Vendure Dashboard imports, which is necessary for // type safety in your dashboard extensions. // This path assumes a root-level tsconfig.json file. // You may need to adjust it if your project structure is different. "@/vdb/*": [ "./node_modules/@vendure/dashboard/src/lib/*" ] } ``` -------------------------------- ### Basic ConfigArgs Example Source: https://docs.vendure.io/current/core/reference/typescript-api/configurable-operation-def/config-args Defines basic arguments with string, integer, and boolean types. ```typescript { apiKey: { type: 'string' }, maxRetries: { type: 'int' }, logErrors: { type: 'boolean' }, } ``` -------------------------------- ### Handle Bearer Token Authentication Source: https://docs.vendure.io/current/core/storefront/connect-api This example demonstrates how to manage bearer token authentication by reading tokens from response headers and attaching them to subsequent requests. It assumes a GraphQL client setup and checks for the 'vendure-auth-token' header. ```typescript let token: string | undefined = localStorage.getItem('token') export async function request(query: string, variables: any) { // If we already know the token, set the Authorization header. const headers = token ? { Authorization: `Bearer ${token}` } : {}; const response = await someGraphQlClient(query, variables, headers); // Check the response headers to see if Vendure has set the // auth token. The header key "vendure-auth-token" may be set to // a custom value with the authOptions.authTokenHeaderKey config option. const authToken = response.headers.get('vendure-auth-token'); if (authToken != null) { token = authToken; } return response.data; } ``` -------------------------------- ### Create New Strapi Project Source: https://docs.vendure.io/current/core/how-to/cms-integration-plugin Initialize a new Strapi project using the Strapi CLI. Follow the prompts to select installation type, database client, and TypeScript usage. ```bash npx create-strapi-app@latest strapi-integration-app cd strapi-integration-app ``` -------------------------------- ### Using useInjector to Inject Services Source: https://docs.vendure.io/current/core/reference/admin-ui-api/react-hooks/use-injector Demonstrates how to use the useInjector hook to get an instance of an Angular service (NotificationService) and call its methods within a React component. Ensure the service is correctly provided in your Angular setup. ```typescript import { useInjector } from '@vendure/admin-ui/react'; import { NotificationService } from '@vendure/admin-ui/core'; export const MyComponent = () => { const notificationService = useInjector(NotificationService); const handleClick = () => { notificationService.success('Hello world!'); }; // ... return
...
; } ``` -------------------------------- ### Redis Session Cache Strategy Implementation Source: https://docs.vendure.io/current/core/reference/typescript-api/auth/session-cache-strategy An example implementation of SessionCacheStrategy using Redis for caching session data. Requires the 'ioredis' package. Initializes a Redis client and provides methods for getting, setting, and deleting cached sessions. ```typescript import { CachedSession, Logger, SessionCacheStrategy, VendurePlugin } from '@vendure/core'; import { Redis, RedisOptions } from 'ioredis'; export interface RedisSessionCachePluginOptions { namespace?: string; redisOptions?: RedisOptions; } const loggerCtx = 'RedisSessionCacheStrategy'; const DEFAULT_NAMESPACE = 'vendure-session-cache'; const DEFAULT_TTL = 86400; export class RedisSessionCacheStrategy implements SessionCacheStrategy { private client: Redis; constructor(private options: RedisSessionCachePluginOptions) {} init() { this.client = new Redis(this.options.redisOptions as RedisOptions); this.client.on('error', err => Logger.error(err.message, loggerCtx, err.stack)); } async destroy() { await this.client.quit(); } async get(sessionToken: string): Promise { try { const retrieved = await this.client.get(this.namespace(sessionToken)); if (retrieved) { try { return JSON.parse(retrieved); } catch (e: any) { Logger.error(`Could not parse cached session data: ${e.message}`, loggerCtx); } } } catch (e: any) { Logger.error(`Could not get cached session: ${e.message}`, loggerCtx); } } async set(session: CachedSession) { try { await this.client.set(this.namespace(session.token), JSON.stringify(session), 'EX', DEFAULT_TTL); } catch (e: any) { Logger.error(`Could not set cached session: ${e.message}`, loggerCtx); } } async delete(sessionToken: string) { try { await this.client.del(this.namespace(sessionToken)); } catch (e: any) { Logger.error(`Could not delete cached session: ${e.message}`, loggerCtx); } } clear() { // not implemented } private namespace(key: string) { return `${this.options.namespace ?? DEFAULT_NAMESPACE}:${key}`; } } @VendurePlugin({ configuration: config => { config.authOptions.sessionCacheStrategy = new RedisSessionCacheStrategy( RedisSessionCachePlugin.options, ); return config; }, }) export class RedisSessionCachePlugin { static options: RedisSessionCachePluginOptions; static init(options: RedisSessionCachePluginOptions) { this.options = options; return this; } } ``` -------------------------------- ### Database Addon Configuration Source: https://docs.vendure.io/current/core/deployment/deploy-to-northflank Sets up a PostgreSQL database addon with specified version, deployment plan, and storage settings. ```json { "kind": "Addon", "spec": { "name": "database", "type": "postgres", "version": "14-latest", "billing": { "deploymentPlan": "nf-compute-20", "storageClass": "ssd", "storage": 4096, "replicas": 1 }, "tlsEnabled": false, "externalAccessEnabled": false, "ipPolicies": [], "pitrEnabled": false } } ``` -------------------------------- ### Using useRichTextEditor Hook Source: https://docs.vendure.io/current/core/reference/admin-ui-api/react-hooks/use-rich-text-editor This example demonstrates how to use the useRichTextEditor hook to get access to the ProseMirror editor instance. It initializes the editor with custom attributes and an onTextInput callback, and returns a ref to be attached to the editor's container element. ```typescript import { useRichTextEditor } from '@vendure/admin-ui/react'; import React from 'react'; export function Component() { const { ref, editor } = useRichTextEditor({ attributes: { class: '' }, onTextInput: (text) => console.log(text), isReadOnly: () => false, }); return
} ``` -------------------------------- ### Asynchronous Custom Field Validation with Injector Source: https://docs.vendure.io/current/core/developer-guide/custom-fields Example of an asynchronous validation function for a string custom field. It uses the Injector to get a service and perform an asynchronous validation check, returning a simple string error message if invalid. ```typescript const config = { // ... customFields: { ProductVariant: [ { name: 'partCode', type: 'string', validate: async (value, injector, ctx) => { const partCodeService = injector.get(PartCodeService); const isValid = await partCodeService.validateCode(value); if (!isValid) { return `Part code ${value} is not valid`; } }, }, ] } }; ``` -------------------------------- ### Example getKey Function Implementation Source: https://docs.vendure.io/current/core/reference/typescript-api/cache/cache-config Provides an example of how to implement the `getKey` function to generate a namespaced cache key. It's recommended to namespace keys to prevent conflicts. ```typescript getKey: id => `MyStrategy:getProductVariantIds:${id}` ``` -------------------------------- ### AI Migration Prompt Example Source: https://docs.vendure.io/current/core/extending-the-dashboard/migration This is a prompt structure to be used with AI assistants like Claude Code or Codex for migrating Vendure Admin UI plugins. It guides the AI through the migration process by outlining general rules, directory structures, and specific component migration tasks. ```markdown ## Instructions 1. If not explicitly stated by the user, find out which plugin they want to migrate. 2. Read and understand the overall rules for migration - the "General" section below - the "Common Tasks" section below 3. Check the tsconfig setup (see "TSConfig setup" section). This may or may not already be set up. - the "TSConfig setup" section below 4. Identify each part of the Admin UI extensions that needs to be migrated, and use the data from the appropriate sections to guide the migration: - the "Forms" section below - the "Custom Field Inputs" section below - the "List Pages" section below - the "Detail Pages" section below - the "Adding Nav Menu Items" section below - the "Action Bar Items" section below - the "Custom Detail Components" section below - the "Page Tabs" section below - the "Widgets" section below 5. Ensure you have followed the instructions marked "Important" for each section ## General - For short we use "old" to refer to code written for the Angular Admin UI, and "new" for the React Dashboard - old code is usually in a plugin's "ui" dir - new code should be in a plugin's "dashboard" dir - new code imports all components from `@vendure/dashboard`. This includes re-exports of common third-party utilities: - `useQuery`, `useMutation`, `useQueryClient` etc. (TanStack Query) - `Link`, `useNavigate`, `useRouter` etc. (TanStack Router) - `useForm`, `useFormContext`, `Controller` etc. (React Hook Form) - `toast` (Sonner) - The following are imported from their own packages: - hooks or anything else needed from `react` - icons from `lucide-react` - for i18n: `Trans`, `useLingui` from `@lingui/react/macro` - Default to the style conventions of the current project as much as possible (single vs double quotes, indent size etc) ## Directory Structure Given as an example - projects may differ in conventions ### Old ``` - /path/to/plugin - /ui - providers.ts - routes.ts - /components - /example - example.component.ts - example.component.html - example.component.scss - example.graphql.ts ``` ``` -------------------------------- ### ProductService Example Source: https://docs.vendure.io/current/core/developer-guide/the-service-layer A simplified example of a Vendure ProductService, demonstrating the findOne method for retrieving a product by ID within a channel and ensuring it's not deleted. It utilizes TransactionalConnection for database access and TranslatorService for localization. ```typescript import { Injectable } from '@nestjs/common'; import { IsNull } from 'typeorm'; import { ID, Product, RequestContext, TransactionalConnection, TranslatorService } from '@vendure/core'; @Injectable() export class ProductService { constructor(private connection: TransactionalConnection, private translator: TranslatorService){} /** * @description * Returns a Product with the given id, or undefined if not found. */ async findOne(ctx: RequestContext, productId: ID): Promise { const product = await this.connection.findOneInChannel(ctx, Product, productId, ctx.channelId, { where: { deletedAt: IsNull(), }, }); if (!product) { return; } return this.translator.translate(product, ctx); } // ... other methods findMany() {} create() {} update() {} } ``` -------------------------------- ### Deployment Service Configuration Source: https://docs.vendure.io/current/core/deployment/deploy-to-northflank Sets up the application server deployment, including instance count, storage, Docker command, and exposed ports. ```json { "kind": "DeploymentService", "ref": "server", "spec": { "name": "server", "billing": { "deploymentPlan": "nf-compute-20" }, "deployment": { "instances": 1, "storage": { "ephemeralStorage": { "storageSize": 1024 }, "shmSize": 64 }, "docker": { "configType": "customCommand", "customCommand": "yarn start:server" }, "internal": { "id": "${refs.builder.id}", "branch": "master", "buildSHA": "latest" } }, "ports": [ { "name": "app", "internalPort": 3000, "public": true, "protocol": "HTTP", "security": { "credentials": [], "policies": [] }, "domains": [] } ], "runtimeEnvironment": {} } } ``` -------------------------------- ### Install ioredis Package Source: https://docs.vendure.io/current/core/reference/typescript-api/cache/redis-cache-plugin To use the RedisCachePlugin, you must manually install the 'ioredis' package. This command installs version 5.3.2 or later. ```shell npm install ioredis@^5.3.2 ``` -------------------------------- ### Configure Database Connection Options Source: https://docs.vendure.io/current/core/deployment/deploy-to-digital-ocean-app-platform Set up database connection details using environment variables for PostgreSQL. Ensure SSL is configured if a CA certificate is provided. ```typescript import { VendureConfig } from '@vendure/core'; export const config: VendureConfig = { // ... dbConnectionOptions: { // ... type: 'postgres', database: process.env.DB_NAME, host: process.env.DB_HOST, port: +process.env.DB_PORT, username: process.env.DB_USERNAME, password: process.env.DB_PASSWORD, ssl: process.env.DB_CA_CERT ? { ca: process.env.DB_CA_CERT, } : undefined, }, }; ``` -------------------------------- ### Install AWS SDK Packages Source: https://docs.vendure.io/current/core/reference/core-plugins/asset-server-plugin/s3asset-storage-strategy Before using the S3AssetStorageStrategy, install the necessary AWS SDK packages. This command installs both the S3 client and the storage utility. ```sh npm install @aws-sdk/client-s3 @aws-sdk/lib-storage ``` -------------------------------- ### Example Payment Method Handler Implementation Source: https://docs.vendure.io/current/core/reference/typescript-api/payment/payment-method-handler This example demonstrates how to create a custom PaymentMethodHandler. It shows the implementation of `createPayment` to interact with a mock payment SDK and `settlePayment`. Ensure you have the necessary SDK and configuration arguments. ```typescript import { PaymentMethodHandler, CreatePaymentResult, SettlePaymentResult, LanguageCode } from '@vendure/core'; // A mock 3rd-party payment SDK import gripeSDK from 'gripe'; export const examplePaymentHandler = new PaymentMethodHandler({ code: 'example-payment-provider', description: [{ languageCode: LanguageCode.en, value: 'Example Payment Provider', }], args: { apiKey: { type: 'string' }, }, createPayment: async (ctx, order, amount, args, metadata): Promise => { try { const result = await gripeSDK.charges.create({ amount, apiKey: args.apiKey, source: metadata.authToken, }); return { amount: order.total, state: 'Settled' as const, transactionId: result.id.toString(), metadata: result.outcome, }; } catch (err: any) { return { amount: order.total, state: 'Declined' as const, metadata: { errorMessage: err.message, }, }; } }, settlePayment: async (ctx, order, payment, args): Promise => { return { success: true }; } }); ``` -------------------------------- ### Implement Default Strategy Source: https://docs.vendure.io/current/core/developer-guide/custom-strategies-in-plugins Create a default implementation of your strategy. Use the `init` method to inject dependencies and perform setup, and `destroy` for cleanup. The `processData` method uses an injected service, and `validateInput` performs basic validation. ```typescript import { Injector, RequestContext, Logger } from '@vendure/core'; import { MyCustomStrategy } from './my-custom-strategy'; import { SomeOtherService } from '../services/some-other.service'; import { loggerCtx } from '../constants'; export class DefaultMyCustomStrategy implements MyCustomStrategy { private someOtherService: SomeOtherService; async init(injector: Injector): Promise { // Inject dependencies during the init phase this.someOtherService = injector.get(SomeOtherService); // Perform any setup logic Logger.info('DefaultMyCustomStrategy initialized', loggerCtx); } async destroy(): Promise { // Clean up resources if needed Logger.info('DefaultMyCustomStrategy destroyed', loggerCtx); } async processData(ctx: RequestContext, data: any): Promise { // Validate input first if (!this.validateInput(data)) { throw new Error('Invalid input data'); } // Use injected service to process data const result = await this.someOtherService.doSomething(ctx, data); // ... do something with the result return result; } validateInput(data: any): boolean { return data != null && typeof data === 'object'; } } ``` -------------------------------- ### Install dataloader package Source: https://docs.vendure.io/current/core/developer-guide/dataloaders Install the dataloader npm package. ```bash npm install dataloader ``` -------------------------------- ### Include Next.js Storefront Option Source: https://docs.vendure.io/current/core/getting-started/installation During project creation, you can choose to include the official Next.js storefront starter. This is optional but recommended for a complete setup. ```console ┌ Let's create a Vendure App ✨ │ ◇ How should we proceed? │ Quick Start │ ◇ Using port 3000 │ ◇ Docker is running │ ◆ Would you like to include the Next.js storefront? # [!code highlight] │ ○ No # [!code highlight] │ ● Yes # [!code highlight] └ # [!code highlight] ``` -------------------------------- ### Install Vendure Dashboard Package Source: https://docs.vendure.io/current/core/extending-the-dashboard/getting-started Install the necessary package for the Vendure Dashboard. ```bash npm install @vendure/dashboard ``` -------------------------------- ### Example LocalizedStringArray Source: https://docs.vendure.io/current/core/reference/typescript-api/configurable-operation-def/localized-string-array An example of how to define a LocalizedStringArray with English, German, and Chinese values. ```typescript const title: LocalizedStringArray = [ { languageCode: LanguageCode.en, value: 'English Title' }, { languageCode: LanguageCode.de, value: 'German Title' }, { languageCode: LanguageCode.zh, value: 'Chinese Title' }, ] ``` -------------------------------- ### GraphQL Data Access Example (Old) Source: https://docs.vendure.io/current/core/extending-the-dashboard/migration Demonstrates how to query customer data using the DataService and a GraphQL query definition. ```typescript import { DataService } from '@vendure/admin-ui/core'; import { graphql } from "../gql"; export const GET_CUSTOMER_NAME = graphql(` query GetCustomerName($id: ID!) { customer(id: $id) { id firstName lastName addresses { ...AddressFragment } } } `); this.dataService.query(GET_CUSTOMER_NAME, { id: customerId, }), ``` -------------------------------- ### Health Check Response Example Source: https://docs.vendure.io/current/core/deployment/using-docker Example JSON response from a healthy worker. ```json { "status": "ok" } ``` -------------------------------- ### Product Variant Prices Example Source: https://docs.vendure.io/current/core/core-concepts/money This JSON shows an example response from a query for a product's variant prices, illustrating how monetary values are stored in minor units. ```json { "data": { "product": { "id": "42", "variants": [ { "id": "74", "name": "Bonsai Tree", "currencyCode": "USD", "price": 1999, "priceWithTax": 2399 } ] } } } ``` -------------------------------- ### DashboardPlugin Initialization Example Source: https://docs.vendure.io/current/core/reference/core-plugins/dashboard-plugin Configure the DashboardPlugin with custom route, app directory for production builds, and Vite development server port. ```typescript import { DashboardPlugin } from '@vendure/dashboard/plugin'; const config: VendureConfig = { // Add an instance of the plugin to the plugins array plugins: [ DashboardPlugin.init({ route: 'dashboard', appDir: './dist/dashboard', // Optional: customize Vite dev server port (defaults to 5173) viteDevServerPort: 3000, }), ], }; ``` -------------------------------- ### SharpAssetPreviewStrategy Source: https://docs.vendure.io/current/core/reference/core-plugins/asset-server-plugin/sharp-asset-preview-strategy Initializes the SharpAssetPreviewStrategy with optional configuration for image output. ```APIDOC ## new SharpAssetPreviewStrategy(config?: SharpAssetPreviewConfig) ### Description Initializes the SharpAssetPreviewStrategy with optional configuration for image output. ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Constructor Signature ```typescript constructor(config?: SharpAssetPreviewConfig) ``` ### Configuration Options (SharpAssetPreviewConfig) - **maxHeight** (number) - Optional - The max height in pixels of a generated preview image. Defaults to 1600. - **maxWidth** (number) - Optional - The max width in pixels of a generated preview image. Defaults to 1600. - **jpegOptions** (sharp.JpegOptions) - Optional - Set Sharp's options for encoding jpeg files. - **pngOptions** (sharp.PngOptions) - Optional - Set Sharp's options for encoding png files. - **webpOptions** (sharp.WebpOptions) - Optional - Set Sharp's options for encoding webp files. - **gifOptions** (sharp.GifOptions) - Optional - Set Sharp's options for encoding gif files. - **avifOptions** (sharp.AvifOptions) - Optional - Set Sharp's options for encoding avif files. ``` -------------------------------- ### Install Elasticsearch Plugin Source: https://docs.vendure.io/current/community-plugins/elasticsearch-plugin Install the necessary packages for the Elasticsearch plugin using npm. ```bash npm install @elastic/elasticsearch @vendure/elasticsearch-plugin ``` -------------------------------- ### Lazy Query Example Source: https://docs.vendure.io/current/core/reference/admin-ui-api/react-hooks/use-lazy-query Demonstrates how to use the useLazyQuery hook to fetch product data. It includes setting up the query, defining the response type, and handling the lazy execution with a button click. The snippet also shows how to display loading and error states, and render the fetched data. ```typescript import { useLazyQuery } from '@vendure/admin-ui/react'; import { gql } from 'graphql-tag'; const GET_PRODUCT = gql` query GetProduct($id: ID!) { product(id: $id) { id name description } } `; type ProductResponse = { product: { name: string description: string } } export const MyComponent = () => { const [getProduct, { data, loading, error }] = useLazyQuery(GET_PRODUCT, { refetchOnChannelChange: true }); const handleClick = () => { getProduct({ id: '1', }).then(result => { // do something with the result }); }; if (loading) return
Loading...
; if (error) return
Error! { error }
; return (
{data && (

{data.product.name}

{data.product.description}

)}
); }; ``` -------------------------------- ### Install Vendure CLI with yarn Source: https://docs.vendure.io/current/core/developer-guide/cli Install the Vendure CLI as a development dependency using yarn. ```bash yarn add -D @vendure/cli ``` -------------------------------- ### Create a New Vendure Project Source: https://docs.vendure.io/current/core/getting-started/installation Use this command to scaffold a new Vendure project. Replace 'my-shop' with your desired project name. ```bash npx @vendure/create my-shop ``` -------------------------------- ### Install Vendure CLI with npm Source: https://docs.vendure.io/current/core/developer-guide/cli Install the Vendure CLI as a development dependency using npm. ```bash npm install -D @vendure/cli ``` -------------------------------- ### Basic Vendure Server Bootstrap Source: https://docs.vendure.io/current/core/reference/typescript-api/common/bootstrap This is the primary entry point for starting a Vendure application. It requires the Vendure configuration object. ```typescript import { bootstrap, } from '@vendure/core'; import { config } from './vendure-config'; bootstrap(config).catch(err => { console.log(err); process.exit(1); }); ```