Просмотр исходного кода

feat(core): Add means to selectively ignore plugin compatibility errors

Closes #2958
Michael Bromley 1 год назад
Родитель
Сommit
e362475cb4
22 измененных файлов с 303 добавлено и 56 удалено
  1. 18 18
      docs/docs/reference/core-plugins/asset-server-plugin/asset-server-options.md
  2. 2 1
      docs/docs/reference/core-plugins/asset-server-plugin/s3asset-storage-strategy.md
  3. 36 0
      docs/docs/reference/graphql-api/admin/object-types.md
  4. 8 0
      docs/docs/reference/graphql-api/shop/object-types.md
  5. 46 2
      docs/docs/reference/typescript-api/common/bootstrap.md
  6. 1 1
      docs/docs/reference/typescript-api/common/currency-code.md
  7. 1 1
      docs/docs/reference/typescript-api/common/job-state.md
  8. 1 1
      docs/docs/reference/typescript-api/common/language-code.md
  9. 1 1
      docs/docs/reference/typescript-api/common/permission.md
  10. 7 0
      docs/docs/reference/typescript-api/custom-fields/index.md
  11. 12 2
      docs/docs/reference/typescript-api/entities/history-entry.md
  12. 12 2
      docs/docs/reference/typescript-api/entities/payment.md
  13. 12 2
      docs/docs/reference/typescript-api/entities/refund.md
  14. 11 1
      docs/docs/reference/typescript-api/entities/session.md
  15. 12 2
      docs/docs/reference/typescript-api/entities/shipping-line.md
  16. 12 2
      docs/docs/reference/typescript-api/entities/stock-level.md
  17. 12 2
      docs/docs/reference/typescript-api/entities/stock-movement.md
  18. 7 2
      docs/docs/reference/typescript-api/plugin/vendure-plugin-metadata.md
  19. 1 1
      docs/docs/reference/typescript-api/plugin/vendure-plugin.md
  20. 9 3
      docs/docs/reference/typescript-api/worker/bootstrap-worker.md
  21. 77 12
      packages/core/src/bootstrap.ts
  22. 5 0
      packages/core/src/plugin/vendure-plugin.ts

+ 18 - 18
docs/docs/reference/core-plugins/asset-server-plugin/asset-server-options.md

@@ -26,8 +26,8 @@ interface AssetServerOptions {
     imageTransformStrategy?: ImageTransformStrategy | ImageTransformStrategy[];
     namingStrategy?: AssetNamingStrategy;
     previewStrategy?: AssetPreviewStrategy;
-    storageStrategyFactory?: (
-        options: AssetServerOptions,
+    storageStrategyFactory?: (
+        options: AssetServerOptions,
     ) => AssetStorageStrategy | Promise<AssetStorageStrategy>;
     cacheHeader?: CacheConfig | string;
 }
@@ -49,12 +49,12 @@ The local directory to which assets will be uploaded when using the <a href='/re
 
 <MemberInfo kind="property" type={`string | ((ctx: <a href='/reference/typescript-api/request/request-context#requestcontext'>RequestContext</a>, identifier: string) =&#62; string)`}   />
 
-The complete URL prefix of the asset files. For example, "https://demo.vendure.io/assets/". A
-function can also be provided to handle more complex cases, such as serving multiple domains
-from a single server. In this case, the function should return a string url prefix.
-
-If not provided, the plugin will attempt to guess based off the incoming
-request and the configured route. However, in all but the simplest cases,
+The complete URL prefix of the asset files. For example, "https://demo.vendure.io/assets/". A
+function can also be provided to handle more complex cases, such as serving multiple domains
+from a single server. In this case, the function should return a string url prefix.
+
+If not provided, the plugin will attempt to guess based off the incoming
+request and the configured route. However, in all but the simplest cases,
 this guess may not yield correct results.
 ### previewMaxWidth
 
@@ -75,12 +75,12 @@ An array of additional <a href='/reference/core-plugins/asset-server-plugin/imag
 
 <MemberInfo kind="property" type={`<a href='/reference/core-plugins/asset-server-plugin/image-transform-strategy#imagetransformstrategy'>ImageTransformStrategy</a> | <a href='/reference/core-plugins/asset-server-plugin/image-transform-strategy#imagetransformstrategy'>ImageTransformStrategy</a>[]`} default={`[]`}  since="3.1.0"  />
 
-The strategy or strategies to use to determine the parameters for transforming an image.
-This can be used to implement custom image transformation logic, for example to
-limit transform parameters to a known set of presets.
-
-If multiple strategies are provided, they will be executed in the order in which they are defined.
-If a strategy throws an error, the image transformation will be aborted and the error
+The strategy or strategies to use to determine the parameters for transforming an image.
+This can be used to implement custom image transformation logic, for example to
+limit transform parameters to a known set of presets.
+
+If multiple strategies are provided, they will be executed in the order in which they are defined.
+If a strategy throws an error, the image transformation will be aborted and the error
 will be logged, with an HTTP 400 response sent to the client.
 ### namingStrategy
 
@@ -91,19 +91,19 @@ Defines how asset files and preview images are named before being saved.
 
 <MemberInfo kind="property" type={`<a href='/reference/typescript-api/assets/asset-preview-strategy#assetpreviewstrategy'>AssetPreviewStrategy</a>`}  since="1.7.0"  />
 
-Defines how previews are generated for a given Asset binary. By default, this uses
+Defines how previews are generated for a given Asset binary. By default, this uses
 the <a href='/reference/core-plugins/asset-server-plugin/sharp-asset-preview-strategy#sharpassetpreviewstrategy'>SharpAssetPreviewStrategy</a>
 ### storageStrategyFactory
 
-<MemberInfo kind="property" type={`(         options: <a href='/reference/core-plugins/asset-server-plugin/asset-server-options#assetserveroptions'>AssetServerOptions</a>,     ) =&#62; <a href='/reference/typescript-api/assets/asset-storage-strategy#assetstoragestrategy'>AssetStorageStrategy</a> | Promise&#60;<a href='/reference/typescript-api/assets/asset-storage-strategy#assetstoragestrategy'>AssetStorageStrategy</a>&#62;`} default={`() =&#62; <a href='/reference/core-plugins/asset-server-plugin/local-asset-storage-strategy#localassetstoragestrategy'>LocalAssetStorageStrategy</a>`}   />
+<MemberInfo kind="property" type={`(
         options: <a href='/reference/core-plugins/asset-server-plugin/asset-server-options#assetserveroptions'>AssetServerOptions</a>,
     ) =&#62; <a href='/reference/typescript-api/assets/asset-storage-strategy#assetstoragestrategy'>AssetStorageStrategy</a> | Promise&#60;<a href='/reference/typescript-api/assets/asset-storage-strategy#assetstoragestrategy'>AssetStorageStrategy</a>&#62;`} default={`() =&#62; <a href='/reference/core-plugins/asset-server-plugin/local-asset-storage-strategy#localassetstoragestrategy'>LocalAssetStorageStrategy</a>`}   />
 
-A function which can be used to configure an <a href='/reference/typescript-api/assets/asset-storage-strategy#assetstoragestrategy'>AssetStorageStrategy</a>. This is useful e.g. if you wish to store your assets
+A function which can be used to configure an <a href='/reference/typescript-api/assets/asset-storage-strategy#assetstoragestrategy'>AssetStorageStrategy</a>. This is useful e.g. if you wish to store your assets
 using a cloud storage provider. By default, the <a href='/reference/core-plugins/asset-server-plugin/local-asset-storage-strategy#localassetstoragestrategy'>LocalAssetStorageStrategy</a> is used.
 ### cacheHeader
 
 <MemberInfo kind="property" type={`<a href='/reference/core-plugins/asset-server-plugin/cache-config#cacheconfig'>CacheConfig</a> | string`} default={`'public, max-age=15552000'`}  since="1.9.3"  />
 
-Configures the `Cache-Control` directive for response to control caching in browsers and shared caches (e.g. Proxies, CDNs).
+Configures the `Cache-Control` directive for response to control caching in browsers and shared caches (e.g. Proxies, CDNs).
 Defaults to publicly cached for 6 months.
 
 

+ 2 - 1
docs/docs/reference/core-plugins/asset-server-plugin/s3asset-storage-strategy.md

@@ -151,7 +151,8 @@ Using type `any` in order to avoid the need to include `aws-sdk` dependency in g
 
 <GenerationInfo sourceFile="packages/asset-server-plugin/src/config/s3-asset-storage-strategy.ts" sourceLine="119" packageName="@vendure/asset-server-plugin" />
 
-Returns a configured instance of the <a href='/reference/core-plugins/asset-server-plugin/s3asset-storage-strategy#s3assetstoragestrategy'>S3AssetStorageStrategy</a> which can then be passed to the <a href='/reference/core-plugins/asset-server-plugin/asset-server-options#assetserveroptions'>AssetServerOptions</a>`storageStrategyFactory` property.
+Returns a configured instance of the <a href='/reference/core-plugins/asset-server-plugin/s3asset-storage-strategy#s3assetstoragestrategy'>S3AssetStorageStrategy</a> which can then be passed to the <a href='/reference/core-plugins/asset-server-plugin/asset-server-options#assetserveroptions'>AssetServerOptions</a>
+`storageStrategyFactory` property.
 
 Before using this strategy, make sure you have the `@aws-sdk/client-s3` and `@aws-sdk/lib-storage` package installed:
 

+ 36 - 0
docs/docs/reference/graphql-api/admin/object-types.md

@@ -134,6 +134,8 @@ import MemberDescription from '@site/src/components/MemberDescription';
 
 <div class="graphql-code-line ">orderLine: <a href="/reference/graphql-api/admin/object-types#orderline">OrderLine</a>!</div>
 
+<div class="graphql-code-line ">customFields: <a href="/reference/graphql-api/admin/object-types#json">JSON</a></div>
+
 
 <div class="graphql-code-line top-level">&#125;</div>
 </div>
@@ -356,6 +358,8 @@ import MemberDescription from '@site/src/components/MemberDescription';
 
 <div class="graphql-code-line ">orderLine: <a href="/reference/graphql-api/admin/object-types#orderline">OrderLine</a>!</div>
 
+<div class="graphql-code-line ">customFields: <a href="/reference/graphql-api/admin/object-types#json">JSON</a></div>
+
 
 <div class="graphql-code-line top-level">&#125;</div>
 </div>
@@ -847,10 +851,14 @@ import MemberDescription from '@site/src/components/MemberDescription';
 
 <div class="graphql-code-line ">GlobalSettings: [<a href="/reference/graphql-api/admin/object-types#customfieldconfig">CustomFieldConfig</a>!]!</div>
 
+<div class="graphql-code-line ">HistoryEntry: [<a href="/reference/graphql-api/admin/object-types#customfieldconfig">CustomFieldConfig</a>!]!</div>
+
 <div class="graphql-code-line ">Order: [<a href="/reference/graphql-api/admin/object-types#customfieldconfig">CustomFieldConfig</a>!]!</div>
 
 <div class="graphql-code-line ">OrderLine: [<a href="/reference/graphql-api/admin/object-types#customfieldconfig">CustomFieldConfig</a>!]!</div>
 
+<div class="graphql-code-line ">Payment: [<a href="/reference/graphql-api/admin/object-types#customfieldconfig">CustomFieldConfig</a>!]!</div>
+
 <div class="graphql-code-line ">PaymentMethod: [<a href="/reference/graphql-api/admin/object-types#customfieldconfig">CustomFieldConfig</a>!]!</div>
 
 <div class="graphql-code-line ">Product: [<a href="/reference/graphql-api/admin/object-types#customfieldconfig">CustomFieldConfig</a>!]!</div>
@@ -865,14 +873,24 @@ import MemberDescription from '@site/src/components/MemberDescription';
 
 <div class="graphql-code-line ">Promotion: [<a href="/reference/graphql-api/admin/object-types#customfieldconfig">CustomFieldConfig</a>!]!</div>
 
+<div class="graphql-code-line ">Refund: [<a href="/reference/graphql-api/admin/object-types#customfieldconfig">CustomFieldConfig</a>!]!</div>
+
 <div class="graphql-code-line ">Region: [<a href="/reference/graphql-api/admin/object-types#customfieldconfig">CustomFieldConfig</a>!]!</div>
 
 <div class="graphql-code-line ">Seller: [<a href="/reference/graphql-api/admin/object-types#customfieldconfig">CustomFieldConfig</a>!]!</div>
 
+<div class="graphql-code-line ">Session: [<a href="/reference/graphql-api/admin/object-types#customfieldconfig">CustomFieldConfig</a>!]!</div>
+
+<div class="graphql-code-line ">ShippingLine: [<a href="/reference/graphql-api/admin/object-types#customfieldconfig">CustomFieldConfig</a>!]!</div>
+
 <div class="graphql-code-line ">ShippingMethod: [<a href="/reference/graphql-api/admin/object-types#customfieldconfig">CustomFieldConfig</a>!]!</div>
 
+<div class="graphql-code-line ">StockLevel: [<a href="/reference/graphql-api/admin/object-types#customfieldconfig">CustomFieldConfig</a>!]!</div>
+
 <div class="graphql-code-line ">StockLocation: [<a href="/reference/graphql-api/admin/object-types#customfieldconfig">CustomFieldConfig</a>!]!</div>
 
+<div class="graphql-code-line ">StockMovement: [<a href="/reference/graphql-api/admin/object-types#customfieldconfig">CustomFieldConfig</a>!]!</div>
+
 <div class="graphql-code-line ">TaxCategory: [<a href="/reference/graphql-api/admin/object-types#customfieldconfig">CustomFieldConfig</a>!]!</div>
 
 <div class="graphql-code-line ">TaxRate: [<a href="/reference/graphql-api/admin/object-types#customfieldconfig">CustomFieldConfig</a>!]!</div>
@@ -1516,6 +1534,8 @@ import MemberDescription from '@site/src/components/MemberDescription';
 
 <div class="graphql-code-line ">data: <a href="/reference/graphql-api/admin/object-types#json">JSON</a>!</div>
 
+<div class="graphql-code-line ">customFields: <a href="/reference/graphql-api/admin/object-types#json">JSON</a></div>
+
 
 <div class="graphql-code-line top-level">&#125;</div>
 </div>
@@ -2593,6 +2613,8 @@ import MemberDescription from '@site/src/components/MemberDescription';
 
 <div class="graphql-code-line ">metadata: <a href="/reference/graphql-api/admin/object-types#json">JSON</a></div>
 
+<div class="graphql-code-line ">customFields: <a href="/reference/graphql-api/admin/object-types#json">JSON</a></div>
+
 
 <div class="graphql-code-line top-level">&#125;</div>
 </div>
@@ -3226,6 +3248,8 @@ import MemberDescription from '@site/src/components/MemberDescription';
 
 <div class="graphql-code-line ">metadata: <a href="/reference/graphql-api/admin/object-types#json">JSON</a></div>
 
+<div class="graphql-code-line ">customFields: <a href="/reference/graphql-api/admin/object-types#json">JSON</a></div>
+
 
 <div class="graphql-code-line top-level">&#125;</div>
 </div>
@@ -3393,6 +3417,8 @@ import MemberDescription from '@site/src/components/MemberDescription';
 
 <div class="graphql-code-line ">quantity: <a href="/reference/graphql-api/admin/object-types#int">Int</a>!</div>
 
+<div class="graphql-code-line ">customFields: <a href="/reference/graphql-api/admin/object-types#json">JSON</a></div>
+
 
 <div class="graphql-code-line top-level">&#125;</div>
 </div>
@@ -3434,6 +3460,8 @@ import MemberDescription from '@site/src/components/MemberDescription';
 
 <div class="graphql-code-line ">quantity: <a href="/reference/graphql-api/admin/object-types#int">Int</a>!</div>
 
+<div class="graphql-code-line ">customFields: <a href="/reference/graphql-api/admin/object-types#json">JSON</a></div>
+
 
 <div class="graphql-code-line top-level">&#125;</div>
 </div>
@@ -3488,6 +3516,8 @@ import MemberDescription from '@site/src/components/MemberDescription';
 
 <div class="graphql-code-line ">quantity: <a href="/reference/graphql-api/admin/object-types#int">Int</a>!</div>
 
+<div class="graphql-code-line ">customFields: <a href="/reference/graphql-api/admin/object-types#json">JSON</a></div>
+
 
 <div class="graphql-code-line top-level">&#125;</div>
 </div>
@@ -3713,6 +3743,8 @@ import MemberDescription from '@site/src/components/MemberDescription';
 
 <div class="graphql-code-line ">discounts: [<a href="/reference/graphql-api/admin/object-types#discount">Discount</a>!]!</div>
 
+<div class="graphql-code-line ">customFields: <a href="/reference/graphql-api/admin/object-types#json">JSON</a></div>
+
 
 <div class="graphql-code-line top-level">&#125;</div>
 </div>
@@ -3837,6 +3869,8 @@ import MemberDescription from '@site/src/components/MemberDescription';
 
 <div class="graphql-code-line ">quantity: <a href="/reference/graphql-api/admin/object-types#int">Int</a>!</div>
 
+<div class="graphql-code-line ">customFields: <a href="/reference/graphql-api/admin/object-types#json">JSON</a></div>
+
 
 <div class="graphql-code-line top-level">&#125;</div>
 </div>
@@ -3859,6 +3893,8 @@ import MemberDescription from '@site/src/components/MemberDescription';
 
 <div class="graphql-code-line ">stockLocation: <a href="/reference/graphql-api/admin/object-types#stocklocation">StockLocation</a>!</div>
 
+<div class="graphql-code-line ">customFields: <a href="/reference/graphql-api/admin/object-types#json">JSON</a></div>
+
 
 <div class="graphql-code-line top-level">&#125;</div>
 </div>

+ 8 - 0
docs/docs/reference/graphql-api/shop/object-types.md

@@ -1072,6 +1072,8 @@ import MemberDescription from '@site/src/components/MemberDescription';
 
 <div class="graphql-code-line ">data: <a href="/reference/graphql-api/shop/object-types#json">JSON</a>!</div>
 
+<div class="graphql-code-line ">customFields: <a href="/reference/graphql-api/shop/object-types#json">JSON</a></div>
+
 
 <div class="graphql-code-line top-level">&#125;</div>
 </div>
@@ -1942,6 +1944,8 @@ import MemberDescription from '@site/src/components/MemberDescription';
 
 <div class="graphql-code-line ">metadata: <a href="/reference/graphql-api/shop/object-types#json">JSON</a></div>
 
+<div class="graphql-code-line ">customFields: <a href="/reference/graphql-api/shop/object-types#json">JSON</a></div>
+
 
 <div class="graphql-code-line top-level">&#125;</div>
 </div>
@@ -2470,6 +2474,8 @@ import MemberDescription from '@site/src/components/MemberDescription';
 
 <div class="graphql-code-line ">metadata: <a href="/reference/graphql-api/shop/object-types#json">JSON</a></div>
 
+<div class="graphql-code-line ">customFields: <a href="/reference/graphql-api/shop/object-types#json">JSON</a></div>
+
 
 <div class="graphql-code-line top-level">&#125;</div>
 </div>
@@ -2757,6 +2763,8 @@ import MemberDescription from '@site/src/components/MemberDescription';
 
 <div class="graphql-code-line ">discounts: [<a href="/reference/graphql-api/shop/object-types#discount">Discount</a>!]!</div>
 
+<div class="graphql-code-line ">customFields: <a href="/reference/graphql-api/shop/object-types#json">JSON</a></div>
+
 
 <div class="graphql-code-line top-level">&#125;</div>
 </div>

+ 46 - 2
docs/docs/reference/typescript-api/common/bootstrap.md

@@ -11,7 +11,7 @@ import MemberDescription from '@site/src/components/MemberDescription';
 
 ## bootstrap
 
-<GenerationInfo sourceFile="packages/core/src/bootstrap.ts" sourceLine="106" packageName="@vendure/core" />
+<GenerationInfo sourceFile="packages/core/src/bootstrap.ts" sourceLine="159" packageName="@vendure/core" />
 
 Bootstraps the Vendure server. This is the entry point to the application.
 
@@ -49,6 +49,27 @@ bootstrap(config, {
 });
 ```
 
+### Ignoring compatibility errors for plugins
+
+Since v3.1.0, you can ignore compatibility errors for specific plugins by passing the `ignoreCompatibilityErrorsForPlugins` option.
+
+This should be used with caution, only if you are sure that the plugin will still work as expected with the current version of Vendure.
+
+*Example*
+
+```ts
+import { bootstrap } from '@vendure/core';
+import { config } from './vendure-config';
+import { MyPlugin } from './plugins/my-plugin';
+
+bootstrap(config, {
+  // Let's say that `MyPlugin` is not yet compatible with the current version of Vendure
+  // but we know that it will still work as expected, and we are not able to publish
+  // a new version of the plugin right now.
+  ignoreCompatibilityErrorsForPlugins: [MyPlugin],
+});
+```
+
 ```ts title="Signature"
 function bootstrap(userConfig: Partial<VendureConfig>, options?: BootstrapOptions): Promise<INestApplication>
 ```
@@ -73,7 +94,8 @@ Vendure server.
 
 ```ts title="Signature"
 interface BootstrapOptions {
-    nestApplicationOptions: NestApplicationOptions;
+    nestApplicationOptions?: NestApplicationOptions;
+    ignoreCompatibilityErrorsForPlugins?: Array<DynamicModule | Type<any>>;
 }
 ```
 
@@ -84,6 +106,28 @@ interface BootstrapOptions {
 <MemberInfo kind="property" type={`NestApplicationOptions`}   />
 
 These options get passed directly to the `NestFactory.create()` method.
+### ignoreCompatibilityErrorsForPlugins
+
+<MemberInfo kind="property" type={`Array&#60;DynamicModule | Type&#60;any&#62;&#62;`} default={`[]`}  since="3.1.0"  />
+
+By default, if a plugin specifies a compatibility range which does not include the current
+Vendure version, the bootstrap process will fail. This option allows you to ignore compatibility
+errors for specific plugins.
+
+This setting should be used with caution, only if you are sure that the plugin will still
+work as expected with the current version of Vendure.
+
+*Example*
+
+```ts
+import { bootstrap } from '@vendure/core';
+import { config } from './vendure-config';
+import { MyPlugin } from './plugins/my-plugin';
+
+bootstrap(config, {
+ ignoreCompatibilityErrorsForPlugins: [MyPlugin],
+});
+```
 
 
 </div>

+ 1 - 1
docs/docs/reference/typescript-api/common/currency-code.md

@@ -11,7 +11,7 @@ import MemberDescription from '@site/src/components/MemberDescription';
 
 ## CurrencyCode
 
-<GenerationInfo sourceFile="packages/common/src/generated-types.ts" sourceLine="992" packageName="@vendure/common" />
+<GenerationInfo sourceFile="packages/common/src/generated-types.ts" sourceLine="994" packageName="@vendure/common" />
 
 ISO 4217 currency code
 

+ 1 - 1
docs/docs/reference/typescript-api/common/job-state.md

@@ -11,7 +11,7 @@ import MemberDescription from '@site/src/components/MemberDescription';
 
 ## JobState
 
-<GenerationInfo sourceFile="packages/common/src/generated-types.ts" sourceLine="2228" packageName="@vendure/common" />
+<GenerationInfo sourceFile="packages/common/src/generated-types.ts" sourceLine="2238" packageName="@vendure/common" />
 
 The state of a Job in the JobQueue
 

+ 1 - 1
docs/docs/reference/typescript-api/common/language-code.md

@@ -11,7 +11,7 @@ import MemberDescription from '@site/src/components/MemberDescription';
 
 ## LanguageCode
 
-<GenerationInfo sourceFile="packages/common/src/generated-types.ts" sourceLine="2246" packageName="@vendure/common" />
+<GenerationInfo sourceFile="packages/common/src/generated-types.ts" sourceLine="2256" packageName="@vendure/common" />
 
 Languages in the form of a ISO 639-1 language code with optional
 region or script modifier (e.g. de_AT). The selection available is based

+ 1 - 1
docs/docs/reference/typescript-api/common/permission.md

@@ -11,7 +11,7 @@ import MemberDescription from '@site/src/components/MemberDescription';
 
 ## Permission
 
-<GenerationInfo sourceFile="packages/common/src/generated-types.ts" sourceLine="4411" packageName="@vendure/common" />
+<GenerationInfo sourceFile="packages/common/src/generated-types.ts" sourceLine="4422" packageName="@vendure/common" />
 
 Permissions for administrators and customers. Used to control access to
 GraphQL resolvers via the <a href='/reference/typescript-api/request/allow-decorator#allow'>Allow</a> decorator.

+ 7 - 0
docs/docs/reference/typescript-api/custom-fields/index.md

@@ -47,8 +47,10 @@ type CustomFields = {
     FacetValue?: CustomFieldConfig[];
     Fulfillment?: CustomFieldConfig[];
     GlobalSettings?: CustomFieldConfig[];
+    HistoryEntry?: CustomFieldConfig[];
     Order?: CustomFieldConfig[];
     OrderLine?: CustomFieldConfig[];
+    Payment?: CustomFieldConfig[];
     PaymentMethod?: CustomFieldConfig[];
     Product?: CustomFieldConfig[];
     ProductOption?: CustomFieldConfig[];
@@ -56,10 +58,15 @@ type CustomFields = {
     ProductVariant?: CustomFieldConfig[];
     ProductVariantPrice?: CustomFieldConfig[];
     Promotion?: CustomFieldConfig[];
+    Refund?: CustomFieldConfig[];
     Region?: CustomFieldConfig[];
     Seller?: CustomFieldConfig[];
+    Session?: CustomFieldConfig[];
+    ShippingLine?: CustomFieldConfig[];
     ShippingMethod?: CustomFieldConfig[];
+    StockLevel?: CustomFieldConfig[];
     StockLocation?: CustomFieldConfig[];
+    StockMovement?: CustomFieldConfig[];
     TaxCategory?: CustomFieldConfig[];
     TaxRate?: CustomFieldConfig[];
     User?: CustomFieldConfig[];

+ 12 - 2
docs/docs/reference/typescript-api/entities/history-entry.md

@@ -11,13 +11,13 @@ import MemberDescription from '@site/src/components/MemberDescription';
 
 ## HistoryEntry
 
-<GenerationInfo sourceFile="packages/core/src/entity/history-entry/history-entry.entity.ts" sourceLine="14" packageName="@vendure/core" />
+<GenerationInfo sourceFile="packages/core/src/entity/history-entry/history-entry.entity.ts" sourceLine="16" packageName="@vendure/core" />
 
 An abstract entity representing an entry in the history of an Order (<a href='/reference/typescript-api/entities/order-history-entry#orderhistoryentry'>OrderHistoryEntry</a>)
 or a Customer (<a href='/reference/typescript-api/entities/customer-history-entry#customerhistoryentry'>CustomerHistoryEntry</a>).
 
 ```ts title="Signature"
-class HistoryEntry extends VendureEntity {
+class HistoryEntry extends VendureEntity implements HasCustomFields {
     @Index()
     @ManyToOne(type => Administrator)
     administrator?: Administrator;
@@ -27,11 +27,16 @@ class HistoryEntry extends VendureEntity {
     isPublic: boolean;
     @Column('simple-json')
     data: any;
+    @Column(type => CustomHistoryEntryFields)
+    customFields: CustomHistoryEntryFields;
 }
 ```
 * Extends: <code><a href='/reference/typescript-api/entities/vendure-entity#vendureentity'>VendureEntity</a></code>
 
 
+* Implements: <code>HasCustomFields</code>
+
+
 
 <div className="members-wrapper">
 
@@ -55,6 +60,11 @@ class HistoryEntry extends VendureEntity {
 <MemberInfo kind="property" type={`any`}   />
 
 
+### customFields
+
+<MemberInfo kind="property" type={`CustomHistoryEntryFields`}   />
+
+
 
 
 </div>

+ 12 - 2
docs/docs/reference/typescript-api/entities/payment.md

@@ -11,13 +11,13 @@ import MemberDescription from '@site/src/components/MemberDescription';
 
 ## Payment
 
-<GenerationInfo sourceFile="packages/core/src/entity/payment/payment.entity.ts" sourceLine="18" packageName="@vendure/core" />
+<GenerationInfo sourceFile="packages/core/src/entity/payment/payment.entity.ts" sourceLine="20" packageName="@vendure/core" />
 
 A Payment represents a single payment transaction and exists in a well-defined state
 defined by the <a href='/reference/typescript-api/payment/payment-state#paymentstate'>PaymentState</a> type.
 
 ```ts title="Signature"
-class Payment extends VendureEntity {
+class Payment extends VendureEntity implements HasCustomFields {
     constructor(input?: DeepPartial<Payment>)
     @Column() method: string;
     @Money() amount: number;
@@ -32,11 +32,16 @@ class Payment extends VendureEntity {
     order: Order;
     @OneToMany(type => Refund, refund => refund.payment)
     refunds: Refund[];
+    @Column(type => CustomPaymentFields)
+    customFields: CustomPaymentFields;
 }
 ```
 * Extends: <code><a href='/reference/typescript-api/entities/vendure-entity#vendureentity'>VendureEntity</a></code>
 
 
+* Implements: <code>HasCustomFields</code>
+
+
 
 <div className="members-wrapper">
 
@@ -85,6 +90,11 @@ class Payment extends VendureEntity {
 <MemberInfo kind="property" type={`<a href='/reference/typescript-api/entities/refund#refund'>Refund</a>[]`}   />
 
 
+### customFields
+
+<MemberInfo kind="property" type={`CustomPaymentFields`}   />
+
+
 
 
 </div>

+ 12 - 2
docs/docs/reference/typescript-api/entities/refund.md

@@ -11,12 +11,12 @@ import MemberDescription from '@site/src/components/MemberDescription';
 
 ## Refund
 
-<GenerationInfo sourceFile="packages/core/src/entity/refund/refund.entity.ts" sourceLine="17" packageName="@vendure/core" />
+<GenerationInfo sourceFile="packages/core/src/entity/refund/refund.entity.ts" sourceLine="19" packageName="@vendure/core" />
 
 A refund the belongs to an order
 
 ```ts title="Signature"
-class Refund extends VendureEntity {
+class Refund extends VendureEntity implements HasCustomFields {
     constructor(input?: DeepPartial<Refund>)
     @Money() items: number;
     @Money() shipping: number;
@@ -36,11 +36,16 @@ class Refund extends VendureEntity {
     @EntityId()
     paymentId: ID;
     @Column('simple-json') metadata: PaymentMetadata;
+    @Column(type => CustomRefundFields)
+    customFields: CustomRefundFields;
 }
 ```
 * Extends: <code><a href='/reference/typescript-api/entities/vendure-entity#vendureentity'>VendureEntity</a></code>
 
 
+* Implements: <code>HasCustomFields</code>
+
+
 
 <div className="members-wrapper">
 
@@ -109,6 +114,11 @@ class Refund extends VendureEntity {
 <MemberInfo kind="property" type={`PaymentMetadata`}   />
 
 
+### customFields
+
+<MemberInfo kind="property" type={`CustomRefundFields`}   />
+
+
 
 
 </div>

+ 11 - 1
docs/docs/reference/typescript-api/entities/session.md

@@ -17,7 +17,7 @@ A Session is created when a user makes a request to restricted API operations. A
 in the case of un-authenticated users, otherwise it is an <a href='/reference/typescript-api/entities/authenticated-session#authenticatedsession'>AuthenticatedSession</a>.
 
 ```ts title="Signature"
-class Session extends VendureEntity {
+class Session extends VendureEntity implements HasCustomFields {
     @Index({ unique: true })
     @Column()
     token: string;
@@ -33,11 +33,16 @@ class Session extends VendureEntity {
     @Index()
     @ManyToOne(type => Channel)
     activeChannel: Channel | null;
+    @Column(type => CustomSessionFields)
+    customFields: CustomSessionFields;
 }
 ```
 * Extends: <code><a href='/reference/typescript-api/entities/vendure-entity#vendureentity'>VendureEntity</a></code>
 
 
+* Implements: <code>HasCustomFields</code>
+
+
 
 <div className="members-wrapper">
 
@@ -76,6 +81,11 @@ class Session extends VendureEntity {
 <MemberInfo kind="property" type={`<a href='/reference/typescript-api/entities/channel#channel'>Channel</a> | null`}   />
 
 
+### customFields
+
+<MemberInfo kind="property" type={`CustomSessionFields`}   />
+
+
 
 
 </div>

+ 12 - 2
docs/docs/reference/typescript-api/entities/shipping-line.md

@@ -11,14 +11,14 @@ import MemberDescription from '@site/src/components/MemberDescription';
 
 ## ShippingLine
 
-<GenerationInfo sourceFile="packages/core/src/entity/shipping-line/shipping-line.entity.ts" sourceLine="24" packageName="@vendure/core" />
+<GenerationInfo sourceFile="packages/core/src/entity/shipping-line/shipping-line.entity.ts" sourceLine="26" packageName="@vendure/core" />
 
 A ShippingLine is created when a <a href='/reference/typescript-api/entities/shipping-method#shippingmethod'>ShippingMethod</a> is applied to an <a href='/reference/typescript-api/entities/order#order'>Order</a>.
 It contains information about the price of the shipping method, any discounts that were
 applied, and the resulting tax on the shipping method.
 
 ```ts title="Signature"
-class ShippingLine extends VendureEntity {
+class ShippingLine extends VendureEntity implements HasCustomFields {
     constructor(input?: DeepPartial<ShippingLine>)
     @EntityId()
     shippingMethodId: ID | null;
@@ -38,6 +38,8 @@ class ShippingLine extends VendureEntity {
     taxLines: TaxLine[];
     @OneToMany(type => OrderLine, orderLine => orderLine.shippingLine)
     orderLines: OrderLine[];
+    @Column(type => CustomShippingLineFields)
+    customFields: CustomShippingLineFields;
     price: number
     priceWithTax: number
     discountedPrice: number
@@ -51,6 +53,9 @@ class ShippingLine extends VendureEntity {
 * Extends: <code><a href='/reference/typescript-api/entities/vendure-entity#vendureentity'>VendureEntity</a></code>
 
 
+* Implements: <code>HasCustomFields</code>
+
+
 
 <div className="members-wrapper">
 
@@ -99,6 +104,11 @@ class ShippingLine extends VendureEntity {
 <MemberInfo kind="property" type={`<a href='/reference/typescript-api/entities/order-line#orderline'>OrderLine</a>[]`}   />
 
 
+### customFields
+
+<MemberInfo kind="property" type={`CustomShippingLineFields`}   />
+
+
 ### price
 
 <MemberInfo kind="property" type={`number`}   />

+ 12 - 2
docs/docs/reference/typescript-api/entities/stock-level.md

@@ -11,13 +11,13 @@ import MemberDescription from '@site/src/components/MemberDescription';
 
 ## StockLevel
 
-<GenerationInfo sourceFile="packages/core/src/entity/stock-level/stock-level.entity.ts" sourceLine="16" packageName="@vendure/core" />
+<GenerationInfo sourceFile="packages/core/src/entity/stock-level/stock-level.entity.ts" sourceLine="18" packageName="@vendure/core" />
 
 A StockLevel represents the number of a particular <a href='/reference/typescript-api/entities/product-variant#productvariant'>ProductVariant</a> which are available
 at a particular <a href='/reference/typescript-api/entities/stock-location#stocklocation'>StockLocation</a>.
 
 ```ts title="Signature"
-class StockLevel extends VendureEntity {
+class StockLevel extends VendureEntity implements HasCustomFields {
     constructor(input: DeepPartial<StockLevel>)
     @Index()
     @ManyToOne(type => ProductVariant, productVariant => productVariant.stockLevels, { onDelete: 'CASCADE' })
@@ -33,11 +33,16 @@ class StockLevel extends VendureEntity {
     stockOnHand: number;
     @Column()
     stockAllocated: number;
+    @Column(type => CustomStockLevelFields)
+    customFields: CustomStockLevelFields;
 }
 ```
 * Extends: <code><a href='/reference/typescript-api/entities/vendure-entity#vendureentity'>VendureEntity</a></code>
 
 
+* Implements: <code>HasCustomFields</code>
+
+
 
 <div className="members-wrapper">
 
@@ -76,6 +81,11 @@ class StockLevel extends VendureEntity {
 <MemberInfo kind="property" type={`number`}   />
 
 
+### customFields
+
+<MemberInfo kind="property" type={`CustomStockLevelFields`}   />
+
+
 
 
 </div>

+ 12 - 2
docs/docs/reference/typescript-api/entities/stock-movement.md

@@ -11,13 +11,13 @@ import MemberDescription from '@site/src/components/MemberDescription';
 
 ## StockMovement
 
-<GenerationInfo sourceFile="packages/core/src/entity/stock-movement/stock-movement.entity.ts" sourceLine="19" packageName="@vendure/core" />
+<GenerationInfo sourceFile="packages/core/src/entity/stock-movement/stock-movement.entity.ts" sourceLine="21" packageName="@vendure/core" />
 
 A StockMovement is created whenever stock of a particular ProductVariant goes in
 or out.
 
 ```ts title="Signature"
-class StockMovement extends VendureEntity {
+class StockMovement extends VendureEntity implements HasCustomFields {
     @Column({ nullable: false, type: 'varchar' })
     readonly type: StockMovementType;
     @Index()
@@ -30,11 +30,16 @@ class StockMovement extends VendureEntity {
     stockLocationId: ID;
     @Column()
     quantity: number;
+    @Column(type => CustomStockMovementFields)
+    customFields: CustomStockMovementFields;
 }
 ```
 * Extends: <code><a href='/reference/typescript-api/entities/vendure-entity#vendureentity'>VendureEntity</a></code>
 
 
+* Implements: <code>HasCustomFields</code>
+
+
 
 <div className="members-wrapper">
 
@@ -63,6 +68,11 @@ class StockMovement extends VendureEntity {
 <MemberInfo kind="property" type={`number`}   />
 
 
+### customFields
+
+<MemberInfo kind="property" type={`CustomStockMovementFields`}   />
+
+
 
 
 </div>

+ 7 - 2
docs/docs/reference/typescript-api/plugin/vendure-plugin-metadata.md

@@ -68,6 +68,11 @@ guaranteed to be compatible with the current version of Vendure.
 
 To effectively disable this check for a plugin, you can use an overly-permissive string such as `>0.0.0`.
 
+:::note
+Since Vendure v3.1.0, it is possible to ignore compatibility errors for specific plugins by
+passing the `ignoreCompatibilityErrorsForPlugins` option to the <a href='/reference/typescript-api/common/bootstrap#bootstrap'>bootstrap</a> function.
+:::
+
 *Example*
 
 ```ts
@@ -80,7 +85,7 @@ compatibility: '^3.0.0'
 
 ## APIExtensionDefinition
 
-<GenerationInfo sourceFile="packages/core/src/plugin/vendure-plugin.ts" sourceLine="74" packageName="@vendure/core" />
+<GenerationInfo sourceFile="packages/core/src/plugin/vendure-plugin.ts" sourceLine="79" packageName="@vendure/core" />
 
 An object which allows a plugin to extend the Vendure GraphQL API.
 
@@ -128,7 +133,7 @@ Read more about defining custom scalars in the
 
 ## PluginConfigurationFn
 
-<GenerationInfo sourceFile="packages/core/src/plugin/vendure-plugin.ts" sourceLine="112" packageName="@vendure/core" />
+<GenerationInfo sourceFile="packages/core/src/plugin/vendure-plugin.ts" sourceLine="117" packageName="@vendure/core" />
 
 This method is called before the app bootstraps and should be used to perform any needed modifications to the <a href='/reference/typescript-api/configuration/vendure-config#vendureconfig'>VendureConfig</a>.
 

+ 1 - 1
docs/docs/reference/typescript-api/plugin/vendure-plugin.md

@@ -11,7 +11,7 @@ import MemberDescription from '@site/src/components/MemberDescription';
 
 ## VendurePlugin
 
-<GenerationInfo sourceFile="packages/core/src/plugin/vendure-plugin.ts" sourceLine="151" packageName="@vendure/core" />
+<GenerationInfo sourceFile="packages/core/src/plugin/vendure-plugin.ts" sourceLine="156" packageName="@vendure/core" />
 
 The VendurePlugin decorator is a means of configuring and/or extending the functionality of the Vendure server. A Vendure plugin is
 a [Nestjs Module](https://docs.nestjs.com/modules), with optional additional metadata defining things like extensions to the GraphQL API, custom

+ 9 - 3
docs/docs/reference/typescript-api/worker/bootstrap-worker.md

@@ -11,7 +11,7 @@ import MemberDescription from '@site/src/components/MemberDescription';
 
 ## bootstrapWorker
 
-<GenerationInfo sourceFile="packages/core/src/bootstrap.ts" sourceLine="170" packageName="@vendure/core" />
+<GenerationInfo sourceFile="packages/core/src/bootstrap.ts" sourceLine="223" packageName="@vendure/core" />
 
 Bootstraps a Vendure worker. Resolves to a <a href='/reference/typescript-api/worker/vendure-worker#vendureworker'>VendureWorker</a> object containing a reference to the underlying
 NestJs [standalone application](https://docs.nestjs.com/standalone-applications) as well as convenience
@@ -51,14 +51,15 @@ Parameters
 
 ## BootstrapWorkerOptions
 
-<GenerationInfo sourceFile="packages/core/src/bootstrap.ts" sourceLine="58" packageName="@vendure/core" since="2.2.0" />
+<GenerationInfo sourceFile="packages/core/src/bootstrap.ts" sourceLine="82" packageName="@vendure/core" since="2.2.0" />
 
 Additional options that can be used to configure the bootstrap process of the
 Vendure worker.
 
 ```ts title="Signature"
 interface BootstrapWorkerOptions {
-    nestApplicationContextOptions: NestApplicationContextOptions;
+    nestApplicationContextOptions?: NestApplicationContextOptions;
+    ignoreCompatibilityErrorsForPlugins?: Array<DynamicModule | Type<any>>;
 }
 ```
 
@@ -69,6 +70,11 @@ interface BootstrapWorkerOptions {
 <MemberInfo kind="property" type={`NestApplicationContextOptions`}   />
 
 These options get passed directly to the `NestFactory.createApplicationContext` method.
+### ignoreCompatibilityErrorsForPlugins
+
+<MemberInfo kind="property" type={`Array&#60;DynamicModule | Type&#60;any&#62;&#62;`} default={`[]`}  since="3.1.0"  />
+
+See the `ignoreCompatibilityErrorsForPlugins` option in <a href='/reference/typescript-api/common/bootstrap#bootstrapoptions'>BootstrapOptions</a>.
 
 
 </div>

+ 77 - 12
packages/core/src/bootstrap.ts

@@ -1,4 +1,4 @@
-import { INestApplication, INestApplicationContext } from '@nestjs/common';
+import { DynamicModule, INestApplication, INestApplicationContext } from '@nestjs/common';
 import { NestApplicationContextOptions } from '@nestjs/common/interfaces/nest-application-context-options.interface';
 import { NestApplicationOptions } from '@nestjs/common/interfaces/nest-application-options.interface';
 import { NestFactory } from '@nestjs/core';
@@ -43,7 +43,31 @@ export interface BootstrapOptions {
      * @description
      * These options get passed directly to the `NestFactory.create()` method.
      */
-    nestApplicationOptions: NestApplicationOptions;
+    nestApplicationOptions?: NestApplicationOptions;
+    /**
+     * @description
+     * By default, if a plugin specifies a compatibility range which does not include the current
+     * Vendure version, the bootstrap process will fail. This option allows you to ignore compatibility
+     * errors for specific plugins.
+     *
+     * This setting should be used with caution, only if you are sure that the plugin will still
+     * work as expected with the current version of Vendure.
+     *
+     * @example
+     * ```ts
+     * import { bootstrap } from '\@vendure/core';
+     * import { config } from './vendure-config';
+     * import { MyPlugin } from './plugins/my-plugin';
+     *
+     * bootstrap(config, {
+     *  ignoreCompatibilityErrorsForPlugins: [MyPlugin],
+     * });
+     * ```
+     *
+     * @default []
+     * @since 3.1.0
+     */
+    ignoreCompatibilityErrorsForPlugins?: Array<DynamicModule | Type<any>>;
 }
 
 /**
@@ -60,7 +84,15 @@ export interface BootstrapWorkerOptions {
      * @description
      * These options get passed directly to the `NestFactory.createApplicationContext` method.
      */
-    nestApplicationContextOptions: NestApplicationContextOptions;
+    nestApplicationContextOptions?: NestApplicationContextOptions;
+    /**
+     * @description
+     * See the `ignoreCompatibilityErrorsForPlugins` option in {@link BootstrapOptions}.
+     *
+     * @default []
+     * @since 3.1.0
+     */
+    ignoreCompatibilityErrorsForPlugins?: Array<DynamicModule | Type<any>>;
 }
 
 /**
@@ -99,6 +131,27 @@ export interface BootstrapWorkerOptions {
  *   process.exit(1);
  * });
  * ```
+ *
+ * ### Ignoring compatibility errors for plugins
+ *
+ * Since v3.1.0, you can ignore compatibility errors for specific plugins by passing the `ignoreCompatibilityErrorsForPlugins` option.
+ *
+ * This should be used with caution, only if you are sure that the plugin will still work as expected with the current version of Vendure.
+ *
+ * @example
+ * ```ts
+ * import { bootstrap } from '\@vendure/core';
+ * import { config } from './vendure-config';
+ * import { MyPlugin } from './plugins/my-plugin';
+ *
+ * bootstrap(config, {
+ *   // Let's say that `MyPlugin` is not yet compatible with the current version of Vendure
+ *   // but we know that it will still work as expected, and we are not able to publish
+ *   // a new version of the plugin right now.
+ *   ignoreCompatibilityErrorsForPlugins: [MyPlugin],
+ * });
+ * ```
+ *
  * @docsCategory common
  * @docsPage bootstrap
  * @docsWeight 0
@@ -110,7 +163,7 @@ export async function bootstrap(
     const config = await preBootstrapConfig(userConfig);
     Logger.useLogger(config.logger);
     Logger.info(`Bootstrapping Vendure Server (pid: ${process.pid})...`);
-    checkPluginCompatibility(config);
+    checkPluginCompatibility(config, options?.ignoreCompatibilityErrorsForPlugins);
 
     // The AppModule *must* be loaded only after the entities have been set in the
     // config, so that they are available when the AppModule decorator is evaluated.
@@ -176,7 +229,7 @@ export async function bootstrapWorker(
     config.logger.setDefaultContext?.('Vendure Worker');
     Logger.useLogger(config.logger);
     Logger.info(`Bootstrapping Vendure Worker (pid: ${process.pid})...`);
-    checkPluginCompatibility(config);
+    checkPluginCompatibility(config, options?.ignoreCompatibilityErrorsForPlugins);
 
     setProcessContext('worker');
     DefaultLogger.hideNestBoostrapLogs();
@@ -238,7 +291,10 @@ export async function preBootstrapConfig(
     return config;
 }
 
-function checkPluginCompatibility(config: RuntimeVendureConfig): void {
+function checkPluginCompatibility(
+    config: RuntimeVendureConfig,
+    ignoredPlugins: Array<DynamicModule | Type<any>> = [],
+): void {
     for (const plugin of config.plugins) {
         const compatibility = getCompatibility(plugin);
         const pluginName = (plugin as any).name as string;
@@ -248,13 +304,22 @@ function checkPluginCompatibility(config: RuntimeVendureConfig): void {
             );
         } else {
             if (!satisfies(VENDURE_VERSION, compatibility, { loose: true, includePrerelease: true })) {
-                Logger.error(
+                const compatibilityErrorMessage =
                     `Plugin "${pluginName}" is not compatible with this version of Vendure. ` +
-                        `It specifies a semver range of "${compatibility}" but the current version is "${VENDURE_VERSION}".`,
-                );
-                throw new InternalServerError(
-                    `Plugin "${pluginName}" is not compatible with this version of Vendure.`,
-                );
+                    `It specifies a semver range of "${compatibility}" but the current version is "${VENDURE_VERSION}".`;
+                if (ignoredPlugins.includes(plugin)) {
+                    Logger.warn(
+                        compatibilityErrorMessage +
+                            `However, this plugin has been explicitly marked as ignored using the 'ignoreCompatibilityErrorsForPlugins' bootstrap option,` +
+                            ` so it will be loaded anyway.`,
+                    );
+                    continue;
+                } else {
+                    Logger.error(compatibilityErrorMessage);
+                    throw new InternalServerError(
+                        `Plugin "${pluginName}" is not compatible with this version of Vendure.`,
+                    );
+                }
             }
         }
     }

+ 5 - 0
packages/core/src/plugin/vendure-plugin.ts

@@ -54,6 +54,11 @@ export interface VendurePluginMetadata extends ModuleMetadata {
      *
      * To effectively disable this check for a plugin, you can use an overly-permissive string such as `>0.0.0`.
      *
+     * :::note
+     * Since Vendure v3.1.0, it is possible to ignore compatibility errors for specific plugins by
+     * passing the `ignoreCompatibilityErrorsForPlugins` option to the {@link bootstrap} function.
+     * :::
+     *
      * @example
      * ```ts
      * compatibility: '^3.0.0'