From fab07a3b79e6c521371b10feea29a6e3edd7785d Mon Sep 17 00:00:00 2001 From: Michael Bromley Date: Wed, 27 Nov 2024 11:45:08 +0100 Subject: [PATCH] feat(core): Add means to selectively ignore plugin compatibility errors Closes #2958 --- .../asset-server-options.md | 36 ++++---- .../s3asset-storage-strategy.md | 3 +- .../graphql-api/admin/object-types.md | 36 ++++++++ .../graphql-api/shop/object-types.md | 8 ++ .../typescript-api/common/bootstrap.md | 48 +++++++++- .../typescript-api/common/currency-code.md | 2 +- .../typescript-api/common/job-state.md | 2 +- .../typescript-api/common/language-code.md | 2 +- .../typescript-api/common/permission.md | 2 +- .../typescript-api/custom-fields/index.md | 7 ++ .../typescript-api/entities/history-entry.md | 14 ++- .../typescript-api/entities/payment.md | 14 ++- .../typescript-api/entities/refund.md | 14 ++- .../typescript-api/entities/session.md | 12 ++- .../typescript-api/entities/shipping-line.md | 14 ++- .../typescript-api/entities/stock-level.md | 14 ++- .../typescript-api/entities/stock-movement.md | 14 ++- .../plugin/vendure-plugin-metadata.md | 9 +- .../typescript-api/plugin/vendure-plugin.md | 2 +- .../typescript-api/worker/bootstrap-worker.md | 12 ++- packages/core/src/bootstrap.ts | 89 ++++++++++++++++--- packages/core/src/plugin/vendure-plugin.ts | 5 ++ 22 files changed, 303 insertions(+), 56 deletions(-) diff --git a/docs/docs/reference/core-plugins/asset-server-plugin/asset-server-options.md b/docs/docs/reference/core-plugins/asset-server-plugin/asset-server-options.md index cffaf52e34..742766b4c2 100644 --- a/docs/docs/reference/core-plugins/asset-server-plugin/asset-server-options.md +++ b/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; cacheHeader?: CacheConfig | string; } @@ -49,12 +49,12 @@ The local directory to which assets will be uploaded when using the RequestContext, identifier: string) => 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 ImageTransformStrategy | ImageTransformStrategy[]`} 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. AssetPreviewStrategy`} 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 SharpAssetPreviewStrategy ### storageStrategyFactory -AssetServerOptions, ) => AssetStorageStrategy | Promise<AssetStorageStrategy>`} default={`() => LocalAssetStorageStrategy`} /> +AssetServerOptions, ) => AssetStorageStrategy | Promise<AssetStorageStrategy>`} default={`() => LocalAssetStorageStrategy`} /> -A function which can be used to configure an AssetStorageStrategy. This is useful e.g. if you wish to store your assets +A function which can be used to configure an AssetStorageStrategy. This is useful e.g. if you wish to store your assets using a cloud storage provider. By default, the LocalAssetStorageStrategy is used. ### cacheHeader CacheConfig | 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. diff --git a/docs/docs/reference/core-plugins/asset-server-plugin/s3asset-storage-strategy.md b/docs/docs/reference/core-plugins/asset-server-plugin/s3asset-storage-strategy.md index 59f28585f4..0f9cd7268d 100644 --- a/docs/docs/reference/core-plugins/asset-server-plugin/s3asset-storage-strategy.md +++ b/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 -Returns a configured instance of the S3AssetStorageStrategy which can then be passed to the AssetServerOptions`storageStrategyFactory` property. +Returns a configured instance of the S3AssetStorageStrategy which can then be passed to the AssetServerOptions +`storageStrategyFactory` property. Before using this strategy, make sure you have the `@aws-sdk/client-s3` and `@aws-sdk/lib-storage` package installed: diff --git a/docs/docs/reference/graphql-api/admin/object-types.md b/docs/docs/reference/graphql-api/admin/object-types.md index d24c326ae4..2f8588ee64 100644 --- a/docs/docs/reference/graphql-api/admin/object-types.md +++ b/docs/docs/reference/graphql-api/admin/object-types.md @@ -134,6 +134,8 @@ import MemberDescription from '@site/src/components/MemberDescription';
orderLine: OrderLine!
+
customFields: JSON
+
}
@@ -356,6 +358,8 @@ import MemberDescription from '@site/src/components/MemberDescription';
orderLine: OrderLine!
+
customFields: JSON
+
}
@@ -847,10 +851,14 @@ import MemberDescription from '@site/src/components/MemberDescription';
GlobalSettings: [CustomFieldConfig!]!
+
HistoryEntry: [CustomFieldConfig!]!
+
OrderLine: [CustomFieldConfig!]!
+
Payment: [CustomFieldConfig!]!
+
PaymentMethod: [CustomFieldConfig!]!
Product: [CustomFieldConfig!]!
@@ -865,14 +873,24 @@ import MemberDescription from '@site/src/components/MemberDescription';
Promotion: [CustomFieldConfig!]!
+
Refund: [CustomFieldConfig!]!
+
Region: [CustomFieldConfig!]!
Seller: [CustomFieldConfig!]!
+
Session: [CustomFieldConfig!]!
+ +
ShippingLine: [CustomFieldConfig!]!
+
ShippingMethod: [CustomFieldConfig!]!
+
StockLevel: [CustomFieldConfig!]!
+
StockLocation: [CustomFieldConfig!]!
+
StockMovement: [CustomFieldConfig!]!
+
TaxCategory: [CustomFieldConfig!]!
TaxRate: [CustomFieldConfig!]!
@@ -1516,6 +1534,8 @@ import MemberDescription from '@site/src/components/MemberDescription';
data: JSON!
+
customFields: JSON
+
}
@@ -2593,6 +2613,8 @@ import MemberDescription from '@site/src/components/MemberDescription';
metadata: JSON
+
customFields: JSON
+
}
@@ -3226,6 +3248,8 @@ import MemberDescription from '@site/src/components/MemberDescription';
metadata: JSON
+
customFields: JSON
+
}
@@ -3393,6 +3417,8 @@ import MemberDescription from '@site/src/components/MemberDescription';
quantity: Int!
+
customFields: JSON
+
}
@@ -3434,6 +3460,8 @@ import MemberDescription from '@site/src/components/MemberDescription';
quantity: Int!
+
customFields: JSON
+
}
@@ -3488,6 +3516,8 @@ import MemberDescription from '@site/src/components/MemberDescription';
quantity: Int!
+
customFields: JSON
+
}
@@ -3713,6 +3743,8 @@ import MemberDescription from '@site/src/components/MemberDescription';
discounts: [Discount!]!
+
customFields: JSON
+
}
@@ -3837,6 +3869,8 @@ import MemberDescription from '@site/src/components/MemberDescription';
quantity: Int!
+
customFields: JSON
+
}
@@ -3859,6 +3893,8 @@ import MemberDescription from '@site/src/components/MemberDescription';
stockLocation: StockLocation!
+
customFields: JSON
+
}
diff --git a/docs/docs/reference/graphql-api/shop/object-types.md b/docs/docs/reference/graphql-api/shop/object-types.md index bc0ce90f81..d7fb95f797 100644 --- a/docs/docs/reference/graphql-api/shop/object-types.md +++ b/docs/docs/reference/graphql-api/shop/object-types.md @@ -1072,6 +1072,8 @@ import MemberDescription from '@site/src/components/MemberDescription';
data: JSON!
+
customFields: JSON
+
}
@@ -1942,6 +1944,8 @@ import MemberDescription from '@site/src/components/MemberDescription';
metadata: JSON
+
customFields: JSON
+
}
@@ -2470,6 +2474,8 @@ import MemberDescription from '@site/src/components/MemberDescription';
metadata: JSON
+
customFields: JSON
+
}
@@ -2757,6 +2763,8 @@ import MemberDescription from '@site/src/components/MemberDescription';
discounts: [Discount!]!
+
customFields: JSON
+
}
diff --git a/docs/docs/reference/typescript-api/common/bootstrap.md b/docs/docs/reference/typescript-api/common/bootstrap.md index 76434b8202..b4812929ef 100644 --- a/docs/docs/reference/typescript-api/common/bootstrap.md +++ b/docs/docs/reference/typescript-api/common/bootstrap.md @@ -11,7 +11,7 @@ import MemberDescription from '@site/src/components/MemberDescription'; ## bootstrap - + 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, options?: BootstrapOptions): Promise ``` @@ -73,7 +94,8 @@ Vendure server. ```ts title="Signature" interface BootstrapOptions { - nestApplicationOptions: NestApplicationOptions; + nestApplicationOptions?: NestApplicationOptions; + ignoreCompatibilityErrorsForPlugins?: Array>; } ``` @@ -84,6 +106,28 @@ interface BootstrapOptions { These options get passed directly to the `NestFactory.create()` method. +### ignoreCompatibilityErrorsForPlugins + + + +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], +}); +``` diff --git a/docs/docs/reference/typescript-api/common/currency-code.md b/docs/docs/reference/typescript-api/common/currency-code.md index a377e45db1..480a3909ac 100644 --- a/docs/docs/reference/typescript-api/common/currency-code.md +++ b/docs/docs/reference/typescript-api/common/currency-code.md @@ -11,7 +11,7 @@ import MemberDescription from '@site/src/components/MemberDescription'; ## CurrencyCode - + ISO 4217 currency code diff --git a/docs/docs/reference/typescript-api/common/job-state.md b/docs/docs/reference/typescript-api/common/job-state.md index 9046d4117b..389c31462f 100644 --- a/docs/docs/reference/typescript-api/common/job-state.md +++ b/docs/docs/reference/typescript-api/common/job-state.md @@ -11,7 +11,7 @@ import MemberDescription from '@site/src/components/MemberDescription'; ## JobState - + The state of a Job in the JobQueue diff --git a/docs/docs/reference/typescript-api/common/language-code.md b/docs/docs/reference/typescript-api/common/language-code.md index 5c62fe97c1..2c3eed0eb1 100644 --- a/docs/docs/reference/typescript-api/common/language-code.md +++ b/docs/docs/reference/typescript-api/common/language-code.md @@ -11,7 +11,7 @@ import MemberDescription from '@site/src/components/MemberDescription'; ## LanguageCode - + 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 diff --git a/docs/docs/reference/typescript-api/common/permission.md b/docs/docs/reference/typescript-api/common/permission.md index 7f87465ed1..5a8b32f287 100644 --- a/docs/docs/reference/typescript-api/common/permission.md +++ b/docs/docs/reference/typescript-api/common/permission.md @@ -11,7 +11,7 @@ import MemberDescription from '@site/src/components/MemberDescription'; ## Permission - + Permissions for administrators and customers. Used to control access to GraphQL resolvers via the Allow decorator. diff --git a/docs/docs/reference/typescript-api/custom-fields/index.md b/docs/docs/reference/typescript-api/custom-fields/index.md index 59f313cdee..c94c5ce4b4 100644 --- a/docs/docs/reference/typescript-api/custom-fields/index.md +++ b/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[]; diff --git a/docs/docs/reference/typescript-api/entities/history-entry.md b/docs/docs/reference/typescript-api/entities/history-entry.md index 9a441cc086..32583fe535 100644 --- a/docs/docs/reference/typescript-api/entities/history-entry.md +++ b/docs/docs/reference/typescript-api/entities/history-entry.md @@ -11,13 +11,13 @@ import MemberDescription from '@site/src/components/MemberDescription'; ## HistoryEntry - + An abstract entity representing an entry in the history of an Order (OrderHistoryEntry) or a Customer (CustomerHistoryEntry). ```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: VendureEntity +* Implements: HasCustomFields + +
@@ -55,6 +60,11 @@ class HistoryEntry extends VendureEntity { +### customFields + + + +
diff --git a/docs/docs/reference/typescript-api/entities/payment.md b/docs/docs/reference/typescript-api/entities/payment.md index 2e25de0fe5..279e0b9da0 100644 --- a/docs/docs/reference/typescript-api/entities/payment.md +++ b/docs/docs/reference/typescript-api/entities/payment.md @@ -11,13 +11,13 @@ import MemberDescription from '@site/src/components/MemberDescription'; ## Payment - + A Payment represents a single payment transaction and exists in a well-defined state defined by the PaymentState type. ```ts title="Signature" -class Payment extends VendureEntity { +class Payment extends VendureEntity implements HasCustomFields { constructor(input?: DeepPartial) @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: VendureEntity +* Implements: HasCustomFields + +
@@ -85,6 +90,11 @@ class Payment extends VendureEntity { Refund[]`} /> +### customFields + + + +
diff --git a/docs/docs/reference/typescript-api/entities/refund.md b/docs/docs/reference/typescript-api/entities/refund.md index 27030393e0..e06d42174b 100644 --- a/docs/docs/reference/typescript-api/entities/refund.md +++ b/docs/docs/reference/typescript-api/entities/refund.md @@ -11,12 +11,12 @@ import MemberDescription from '@site/src/components/MemberDescription'; ## Refund - + A refund the belongs to an order ```ts title="Signature" -class Refund extends VendureEntity { +class Refund extends VendureEntity implements HasCustomFields { constructor(input?: DeepPartial) @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: VendureEntity +* Implements: HasCustomFields + +
@@ -109,6 +114,11 @@ class Refund extends VendureEntity { +### customFields + + + +
diff --git a/docs/docs/reference/typescript-api/entities/session.md b/docs/docs/reference/typescript-api/entities/session.md index 0519348388..10d8b88426 100644 --- a/docs/docs/reference/typescript-api/entities/session.md +++ b/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 AuthenticatedSession. ```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: VendureEntity +* Implements: HasCustomFields + +
@@ -76,6 +81,11 @@ class Session extends VendureEntity { Channel | null`} /> +### customFields + + + +
diff --git a/docs/docs/reference/typescript-api/entities/shipping-line.md b/docs/docs/reference/typescript-api/entities/shipping-line.md index 560925e96e..8fd01ef28e 100644 --- a/docs/docs/reference/typescript-api/entities/shipping-line.md +++ b/docs/docs/reference/typescript-api/entities/shipping-line.md @@ -11,14 +11,14 @@ import MemberDescription from '@site/src/components/MemberDescription'; ## ShippingLine - + A ShippingLine is created when a ShippingMethod is applied to an Order. 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) @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: VendureEntity +* Implements: HasCustomFields + +
@@ -99,6 +104,11 @@ class ShippingLine extends VendureEntity { OrderLine[]`} /> +### customFields + + + + ### price diff --git a/docs/docs/reference/typescript-api/entities/stock-level.md b/docs/docs/reference/typescript-api/entities/stock-level.md index 5cd76faadb..c385526807 100644 --- a/docs/docs/reference/typescript-api/entities/stock-level.md +++ b/docs/docs/reference/typescript-api/entities/stock-level.md @@ -11,13 +11,13 @@ import MemberDescription from '@site/src/components/MemberDescription'; ## StockLevel - + A StockLevel represents the number of a particular ProductVariant which are available at a particular StockLocation. ```ts title="Signature" -class StockLevel extends VendureEntity { +class StockLevel extends VendureEntity implements HasCustomFields { constructor(input: DeepPartial) @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: VendureEntity +* Implements: HasCustomFields + +
@@ -76,6 +81,11 @@ class StockLevel extends VendureEntity { +### customFields + + + +
diff --git a/docs/docs/reference/typescript-api/entities/stock-movement.md b/docs/docs/reference/typescript-api/entities/stock-movement.md index 90a2575237..3e7165b3e2 100644 --- a/docs/docs/reference/typescript-api/entities/stock-movement.md +++ b/docs/docs/reference/typescript-api/entities/stock-movement.md @@ -11,13 +11,13 @@ import MemberDescription from '@site/src/components/MemberDescription'; ## StockMovement - + 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: VendureEntity +* Implements: HasCustomFields + +
@@ -63,6 +68,11 @@ class StockMovement extends VendureEntity { +### customFields + + + +
diff --git a/docs/docs/reference/typescript-api/plugin/vendure-plugin-metadata.md b/docs/docs/reference/typescript-api/plugin/vendure-plugin-metadata.md index bfe62d883c..d08f59685f 100644 --- a/docs/docs/reference/typescript-api/plugin/vendure-plugin-metadata.md +++ b/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 bootstrap function. +::: + *Example* ```ts @@ -80,7 +85,7 @@ compatibility: '^3.0.0' ## APIExtensionDefinition - + 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 - + This method is called before the app bootstraps and should be used to perform any needed modifications to the VendureConfig. diff --git a/docs/docs/reference/typescript-api/plugin/vendure-plugin.md b/docs/docs/reference/typescript-api/plugin/vendure-plugin.md index fb792537d1..9ec143e67c 100644 --- a/docs/docs/reference/typescript-api/plugin/vendure-plugin.md +++ b/docs/docs/reference/typescript-api/plugin/vendure-plugin.md @@ -11,7 +11,7 @@ import MemberDescription from '@site/src/components/MemberDescription'; ## VendurePlugin - + 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 diff --git a/docs/docs/reference/typescript-api/worker/bootstrap-worker.md b/docs/docs/reference/typescript-api/worker/bootstrap-worker.md index 88f102eb37..7a6b49f58b 100644 --- a/docs/docs/reference/typescript-api/worker/bootstrap-worker.md +++ b/docs/docs/reference/typescript-api/worker/bootstrap-worker.md @@ -11,7 +11,7 @@ import MemberDescription from '@site/src/components/MemberDescription'; ## bootstrapWorker - + Bootstraps a Vendure worker. Resolves to a VendureWorker 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 - + 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>; } ``` @@ -69,6 +70,11 @@ interface BootstrapWorkerOptions { These options get passed directly to the `NestFactory.createApplicationContext` method. +### ignoreCompatibilityErrorsForPlugins + + + +See the `ignoreCompatibilityErrorsForPlugins` option in BootstrapOptions.
diff --git a/packages/core/src/bootstrap.ts b/packages/core/src/bootstrap.ts index 99cb60b22e..3e6ebc330c 100644 --- a/packages/core/src/bootstrap.ts +++ b/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>; } /** @@ -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>; } /** @@ -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> = [], +): 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.`, + ); + } } } } diff --git a/packages/core/src/plugin/vendure-plugin.ts b/packages/core/src/plugin/vendure-plugin.ts index 6fcd4ffe86..794e5d0f9d 100644 --- a/packages/core/src/plugin/vendure-plugin.ts +++ b/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'