Forráskód Böngészése

Merge branch 'master' into minor

Michael Bromley 11 hónapja
szülő
commit
65ad028776
34 módosított fájl, 405 hozzáadás és 218 törlés
  1. 15 0
      CHANGELOG.md
  2. 2 2
      docs/docs/guides/developer-guide/plugins/index.mdx
  3. 54 1
      docs/docs/guides/developer-guide/worker-job-queue/index.mdx
  4. 1 1
      lerna.json
  5. 24 0
      license/signatures/version1/cla.json
  6. 56 56
      package-lock.json
  7. 4 4
      packages/admin-ui-plugin/package.json
  8. 2 2
      packages/admin-ui/package.json
  9. 1 1
      packages/admin-ui/src/lib/core/src/common/version.ts
  10. 5 8
      packages/admin-ui/src/lib/order/src/components/draft-order-variant-selector/draft-order-variant-selector.component.html
  11. 6 10
      packages/admin-ui/src/lib/order/src/components/order-editor/order-editor.component.html
  12. 3 3
      packages/asset-server-plugin/package.json
  13. 3 3
      packages/cli/package.json
  14. 1 1
      packages/common/package.json
  15. 4 1
      packages/core/e2e/cache-service-default.e2e-spec.ts
  16. 2 2
      packages/core/package.json
  17. 50 21
      packages/core/src/api/common/graphql-value-transformer.ts
  18. 1 1
      packages/core/src/api/config/configure-graphql-module.ts
  19. 5 2
      packages/core/src/api/config/graphql-custom-fields.ts
  20. 10 1
      packages/core/src/plugin/default-job-queue-plugin/sql-job-buffer-storage-strategy.ts
  21. 102 54
      packages/core/src/service/services/collection.service.ts
  22. 3 3
      packages/create/package.json
  23. 3 2
      packages/dev-server/index.ts
  24. 9 9
      packages/dev-server/package.json
  25. 3 3
      packages/elasticsearch-plugin/package.json
  26. 3 3
      packages/email-plugin/package.json
  27. 3 3
      packages/harden-plugin/package.json
  28. 3 3
      packages/job-queue-plugin/package.json
  29. 10 1
      packages/job-queue-plugin/src/bullmq/redis-job-buffer-storage-strategy.ts
  30. 4 4
      packages/payments-plugin/package.json
  31. 3 3
      packages/sentry-plugin/package.json
  32. 3 3
      packages/stellate-plugin/package.json
  33. 3 3
      packages/testing/package.json
  34. 4 4
      packages/ui-devkit/package.json

+ 15 - 0
CHANGELOG.md

@@ -1,3 +1,18 @@
+## <small>3.1.3 (2025-02-14)</small>
+
+
+#### Fixes
+
+* **admin-ui** Improve display of OrderLine custom fields in form ([4e92d85](https://github.com/vendure-ecommerce/vendure/commit/4e92d85))
+* **core** Allow non-public customOrderLineFields in admin api (#3357) ([becfe9d](https://github.com/vendure-ecommerce/vendure/commit/becfe9d)), closes [#3357](https://github.com/vendure-ecommerce/vendure/issues/3357)
+* **core** Fix undefined type issue with nested fragment spreads (#3351) ([d0c0454](https://github.com/vendure-ecommerce/vendure/commit/d0c0454)), closes [#3351](https://github.com/vendure-ecommerce/vendure/issues/3351)
+
+#### Perf
+
+* **core** Optimize payload of apply-collection-filters job ([4157033](https://github.com/vendure-ecommerce/vendure/commit/4157033))
+* **core** Optimize payload size for buffered jobs in DB ([f81a908](https://github.com/vendure-ecommerce/vendure/commit/f81a908))
+* **job-queue-plugin** Optimize payload size for buffered jobs in Redis ([7c72352](https://github.com/vendure-ecommerce/vendure/commit/7c72352))
+
 ## <small>3.1.2 (2025-01-22)</small>
 
 

+ 2 - 2
docs/docs/guides/developer-guide/plugins/index.mdx

@@ -216,7 +216,7 @@ By convention, we'll store the entity definitions in the `entities` directory of
 
 ```ts title="src/plugins/wishlist-plugin/entities/wishlist-item.entity.ts"
 import { DeepPartial, ID, ProductVariant, VendureEntity, EntityId } from '@vendure/core';
-import { Column, Entity, ManyToOne } from 'typeorm';
+import { Entity, ManyToOne } from 'typeorm';
 
 @Entity()
 export class WishlistItem extends VendureEntity {
@@ -727,7 +727,7 @@ We can then query the wishlist items:
 
 
 <Tabs>
-<TabItem value="GetWishlist mutation" label="GetWishlist mutation" default>
+<TabItem value="GetWishlist query" label="GetWishlist query" default>
 
 ```graphql
 query GetWishlist {

+ 54 - 1
docs/docs/guides/developer-guide/worker-job-queue/index.mdx

@@ -324,7 +324,7 @@ export class ProductVideoPlugin {}
 
 ### Passing the RequestContext
 
-It is common to need to pass the [RequestContext object](/reference/typescript-api/request/request-context) to the `process` function of a job, since `ctx` is required by many Vendure
+Sometimes you need to pass the [RequestContext object](/reference/typescript-api/request/request-context) to the `process` function of a job, since `ctx` is required by many Vendure
 service methods that you may be using inside your `process` function. However, the `RequestContext` object itself is not serializable,
 so it cannot be passed directly to the `JobQueue.add()` method. Instead, you can serialize the `RequestContext` using the [`RequestContext.serialize()`
 method](/reference/typescript-api/request/request-context/#serialize), and then deserialize it in the `process` function using the static `deserialize` method:
@@ -363,6 +363,59 @@ class ProductExportService implements OnModuleInit {
 }
 ```
 
+:::warning
+Serializing the RequestContext should be done with caution, since it is a relatively large object and will significantly increase the size of the job data.
+
+In cases where the job is created in large quantities (hundreds or thousands of jobs per day), this can lead to performance issues. Especially
+when using the [BullMQJobQueuePlugin](/reference/core-plugins/job-queue-plugin/bull-mqjob-queue-plugin/), which stores the job data in Redis, the
+size of the job data can lead to too much memory usage which can cause the Redis server to crash.
+:::
+
+Instead of serializing the entire RequestContext, consider passing only the necessary data you need and then reconstructing the RequestContext in the `process` function:
+
+```ts
+import { Injectable, OnModuleInit } from '@nestjs/common';
+import { JobQueue, JobQueueService,
+    RequestContext, ID, LanguageCode, RequestContextService } from '@vendure/core';
+
+@Injectable()
+class ProductExportService implements OnModuleInit {
+
+    // highlight-next-line
+    private jobQueue: JobQueue<{ channelToken: string; languageCode: LanguageCode; }>;
+
+    constructor(private jobQueueService: JobQueueService,
+                private requestContextService: RequestContextService) {
+    }
+
+    async onModuleInit() {
+        this.jobQueue = await this.jobQueueService.createQueue({
+            name: 'export-products',
+            process: async job => {
+                // highlight-start
+                // Reconstruct the RequestContext from the passed data
+                const ctx = await this.requestContextService.create({
+                    channelOrToken: job.data.channelToken,
+                    languageCode: job.data.languageCode,
+                })
+                // highlight-end
+                // ... logic to export the product omitted for brevity
+            },
+        });
+    }
+
+    exportAllProducts(ctx: RequestContext) {
+        // highlight-start
+        // Pass only the necessary data
+        return this.jobQueue.add({
+            channelId: ctx.channel.token,
+            languageCode: ctx.languageCode
+        });
+        // highlight-end
+    }
+}
+```
+
 ### Handling job cancellation
 
 It is possible for an administrator to cancel a running job. Doing so will cause the configured job queue strategy to mark the job as cancelled, but

+ 1 - 1
lerna.json

@@ -1,6 +1,6 @@
 {
     "packages": ["packages/*"],
-    "version": "3.1.2",
+    "version": "3.1.3",
     "npmClient": "npm",
     "command": {
         "version": {

+ 24 - 0
license/signatures/version1/cla.json

@@ -479,6 +479,30 @@
       "created_at": "2025-02-07T12:21:59Z",
       "repoId": 136938012,
       "pullRequestNo": 3351
+    },
+    {
+      "name": "kamui",
+      "id": 2255,
+      "comment_id": 2649402776,
+      "created_at": "2025-02-10T22:30:15Z",
+      "repoId": 136938012,
+      "pullRequestNo": 3359
+    },
+    {
+      "name": "hooooooouzx",
+      "id": 50389824,
+      "comment_id": 2656943842,
+      "created_at": "2025-02-13T15:22:59Z",
+      "repoId": 136938012,
+      "pullRequestNo": 3363
+    },
+    {
+      "name": "Ryrahul",
+      "id": 121729670,
+      "comment_id": 2657081786,
+      "created_at": "2025-02-13T16:09:46Z",
+      "repoId": 136938012,
+      "pullRequestNo": 3365
     }
   ]
 }

+ 56 - 56
package-lock.json

@@ -32687,7 +32687,7 @@
         },
         "packages/admin-ui": {
             "name": "@vendure/admin-ui",
-            "version": "3.1.2",
+            "version": "3.1.3",
             "license": "GPL-3.0-or-later",
             "dependencies": {
                 "@angular/animations": "^17.2.4",
@@ -32710,7 +32710,7 @@
                 "@ng-select/ng-select": "^12.0.7",
                 "@ngx-translate/core": "^15.0.0",
                 "@ngx-translate/http-loader": "^8.0.0",
-                "@vendure/common": "^3.1.2",
+                "@vendure/common": "^3.1.3",
                 "@webcomponents/custom-elements": "^1.6.0",
                 "apollo-angular": "^6.0.0",
                 "apollo-upload-client": "^18.0.1",
@@ -32781,7 +32781,7 @@
         },
         "packages/admin-ui-plugin": {
             "name": "@vendure/admin-ui-plugin",
-            "version": "3.1.2",
+            "version": "3.1.3",
             "license": "GPL-3.0-or-later",
             "dependencies": {
                 "date-fns": "^2.30.0",
@@ -32791,9 +32791,9 @@
             "devDependencies": {
                 "@types/express": "^4.17.21",
                 "@types/fs-extra": "^11.0.4",
-                "@vendure/admin-ui": "^3.1.2",
-                "@vendure/common": "^3.1.2",
-                "@vendure/core": "^3.1.2",
+                "@vendure/admin-ui": "^3.1.3",
+                "@vendure/common": "^3.1.3",
+                "@vendure/core": "^3.1.3",
                 "express": "^4.18.3",
                 "rimraf": "^5.0.5",
                 "typescript": "5.4.2"
@@ -32824,7 +32824,7 @@
         },
         "packages/asset-server-plugin": {
             "name": "@vendure/asset-server-plugin",
-            "version": "3.1.2",
+            "version": "3.1.3",
             "license": "GPL-3.0-or-later",
             "dependencies": {
                 "file-type": "^19.0.0",
@@ -32837,8 +32837,8 @@
                 "@types/express": "^4.17.21",
                 "@types/fs-extra": "^11.0.4",
                 "@types/node-fetch": "^2.6.11",
-                "@vendure/common": "^3.1.2",
-                "@vendure/core": "^3.1.2",
+                "@vendure/common": "^3.1.3",
+                "@vendure/core": "^3.1.3",
                 "express": "^4.18.3",
                 "node-fetch": "^2.7.0",
                 "rimraf": "^5.0.5",
@@ -32850,11 +32850,11 @@
         },
         "packages/cli": {
             "name": "@vendure/cli",
-            "version": "3.1.2",
+            "version": "3.1.3",
             "license": "GPL-3.0-or-later",
             "dependencies": {
                 "@clack/prompts": "^0.7.0",
-                "@vendure/common": "^3.1.2",
+                "@vendure/common": "^3.1.3",
                 "change-case": "^4.1.2",
                 "commander": "^11.0.0",
                 "dotenv": "^16.4.5",
@@ -32868,7 +32868,7 @@
                 "vendure": "dist/cli.js"
             },
             "devDependencies": {
-                "@vendure/core": "^3.1.2",
+                "@vendure/core": "^3.1.3",
                 "typescript": "5.3.3"
             },
             "funding": {
@@ -32903,7 +32903,7 @@
         },
         "packages/common": {
             "name": "@vendure/common",
-            "version": "3.1.2",
+            "version": "3.1.3",
             "license": "GPL-3.0-or-later",
             "devDependencies": {
                 "rimraf": "^5.0.5",
@@ -32915,7 +32915,7 @@
         },
         "packages/core": {
             "name": "@vendure/core",
-            "version": "3.1.2",
+            "version": "3.1.3",
             "license": "GPL-3.0-or-later",
             "dependencies": {
                 "@apollo/server": "^4.11.2",
@@ -32927,7 +32927,7 @@
                 "@nestjs/platform-express": "~10.4.12",
                 "@nestjs/terminus": "~10.2.3",
                 "@nestjs/typeorm": "~10.0.2",
-                "@vendure/common": "^3.1.2",
+                "@vendure/common": "^3.1.3",
                 "bcrypt": "^5.1.1",
                 "body-parser": "^1.20.2",
                 "cookie-session": "^2.1.0",
@@ -33083,11 +33083,11 @@
         },
         "packages/create": {
             "name": "@vendure/create",
-            "version": "3.1.2",
+            "version": "3.1.3",
             "license": "GPL-3.0-or-later",
             "dependencies": {
                 "@clack/prompts": "^0.7.0",
-                "@vendure/common": "^3.1.2",
+                "@vendure/common": "^3.1.3",
                 "commander": "^11.0.0",
                 "cross-spawn": "^7.0.3",
                 "fs-extra": "^11.2.0",
@@ -33105,7 +33105,7 @@
                 "@types/fs-extra": "^11.0.4",
                 "@types/handlebars": "^4.1.0",
                 "@types/semver": "^7.5.8",
-                "@vendure/core": "^3.1.2",
+                "@vendure/core": "^3.1.3",
                 "rimraf": "^5.0.5",
                 "ts-node": "^10.9.2",
                 "typescript": "5.3.3"
@@ -33122,21 +33122,21 @@
             }
         },
         "packages/dev-server": {
-            "version": "3.1.2",
+            "version": "3.1.3",
             "license": "GPL-3.0-or-later",
             "dependencies": {
                 "@nestjs/axios": "^3.0.2",
-                "@vendure/admin-ui-plugin": "^3.1.2",
-                "@vendure/asset-server-plugin": "^3.1.2",
-                "@vendure/common": "^3.1.2",
-                "@vendure/core": "^3.1.2",
-                "@vendure/elasticsearch-plugin": "^3.1.2",
-                "@vendure/email-plugin": "^3.1.2",
+                "@vendure/admin-ui-plugin": "^3.1.3",
+                "@vendure/asset-server-plugin": "^3.1.3",
+                "@vendure/common": "^3.1.3",
+                "@vendure/core": "^3.1.3",
+                "@vendure/elasticsearch-plugin": "^3.1.3",
+                "@vendure/email-plugin": "^3.1.3",
                 "typescript": "5.3.3"
             },
             "devDependencies": {
-                "@vendure/testing": "^3.1.2",
-                "@vendure/ui-devkit": "^3.1.2",
+                "@vendure/testing": "^3.1.3",
+                "@vendure/ui-devkit": "^3.1.3",
                 "commander": "^12.0.0",
                 "concurrently": "^8.2.2",
                 "csv-stringify": "^6.4.6",
@@ -33154,7 +33154,7 @@
         },
         "packages/elasticsearch-plugin": {
             "name": "@vendure/elasticsearch-plugin",
-            "version": "3.1.2",
+            "version": "3.1.3",
             "license": "GPL-3.0-or-later",
             "dependencies": {
                 "@elastic/elasticsearch": "~7.9.1",
@@ -33162,8 +33162,8 @@
                 "fast-deep-equal": "^3.1.3"
             },
             "devDependencies": {
-                "@vendure/common": "^3.1.2",
-                "@vendure/core": "^3.1.2",
+                "@vendure/common": "^3.1.3",
+                "@vendure/core": "^3.1.3",
                 "rimraf": "^5.0.5",
                 "typescript": "5.3.3"
             },
@@ -33173,7 +33173,7 @@
         },
         "packages/email-plugin": {
             "name": "@vendure/email-plugin",
-            "version": "3.1.2",
+            "version": "3.1.3",
             "license": "GPL-3.0-or-later",
             "dependencies": {
                 "@types/nodemailer": "^6.4.9",
@@ -33189,8 +33189,8 @@
                 "@types/express": "^4.17.21",
                 "@types/fs-extra": "^11.0.4",
                 "@types/mjml": "^4.7.4",
-                "@vendure/common": "^3.1.2",
-                "@vendure/core": "^3.1.2",
+                "@vendure/common": "^3.1.3",
+                "@vendure/core": "^3.1.3",
                 "rimraf": "^5.0.5",
                 "typescript": "5.3.3"
             },
@@ -33200,14 +33200,14 @@
         },
         "packages/harden-plugin": {
             "name": "@vendure/harden-plugin",
-            "version": "3.1.2",
+            "version": "3.1.3",
             "license": "GPL-3.0-or-later",
             "dependencies": {
                 "graphql-query-complexity": "^0.12.0"
             },
             "devDependencies": {
-                "@vendure/common": "^3.1.2",
-                "@vendure/core": "^3.1.2"
+                "@vendure/common": "^3.1.3",
+                "@vendure/core": "^3.1.3"
             },
             "funding": {
                 "url": "https://github.com/sponsors/michaelbromley"
@@ -33215,12 +33215,12 @@
         },
         "packages/job-queue-plugin": {
             "name": "@vendure/job-queue-plugin",
-            "version": "3.1.2",
+            "version": "3.1.3",
             "license": "GPL-3.0-or-later",
             "devDependencies": {
                 "@google-cloud/pubsub": "^2.8.0",
-                "@vendure/common": "^3.1.2",
-                "@vendure/core": "^3.1.2",
+                "@vendure/common": "^3.1.3",
+                "@vendure/core": "^3.1.3",
                 "bullmq": "^5.4.2",
                 "ioredis": "^5.3.2",
                 "rimraf": "^5.0.5",
@@ -33232,7 +33232,7 @@
         },
         "packages/payments-plugin": {
             "name": "@vendure/payments-plugin",
-            "version": "3.1.2",
+            "version": "3.1.3",
             "license": "GPL-3.0-or-later",
             "dependencies": {
                 "currency.js": "2.0.4"
@@ -33241,9 +33241,9 @@
                 "@mollie/api-client": "^3.7.0",
                 "@types/braintree": "^3.3.11",
                 "@types/localtunnel": "2.0.4",
-                "@vendure/common": "^3.1.2",
-                "@vendure/core": "^3.1.2",
-                "@vendure/testing": "^3.1.2",
+                "@vendure/common": "^3.1.3",
+                "@vendure/core": "^3.1.3",
+                "@vendure/testing": "^3.1.3",
                 "braintree": "^3.22.0",
                 "localtunnel": "2.0.2",
                 "nock": "^13.1.4",
@@ -33297,12 +33297,12 @@
         },
         "packages/sentry-plugin": {
             "name": "@vendure/sentry-plugin",
-            "version": "3.1.2",
+            "version": "3.1.3",
             "license": "GPL-3.0-or-later",
             "devDependencies": {
                 "@sentry/node": "^7.106.1",
-                "@vendure/common": "^3.1.2",
-                "@vendure/core": "^3.1.2"
+                "@vendure/common": "^3.1.3",
+                "@vendure/core": "^3.1.3"
             },
             "funding": {
                 "url": "https://github.com/sponsors/michaelbromley"
@@ -33313,14 +33313,14 @@
         },
         "packages/stellate-plugin": {
             "name": "@vendure/stellate-plugin",
-            "version": "3.1.2",
+            "version": "3.1.3",
             "license": "GPL-3.0-or-later",
             "dependencies": {
                 "node-fetch": "^2.7.0"
             },
             "devDependencies": {
-                "@vendure/common": "^3.1.2",
-                "@vendure/core": "^3.1.2"
+                "@vendure/common": "^3.1.3",
+                "@vendure/core": "^3.1.3"
             },
             "funding": {
                 "url": "https://github.com/sponsors/michaelbromley"
@@ -33328,11 +33328,11 @@
         },
         "packages/testing": {
             "name": "@vendure/testing",
-            "version": "3.1.2",
+            "version": "3.1.3",
             "license": "GPL-3.0-or-later",
             "dependencies": {
                 "@graphql-typed-document-node/core": "^3.2.0",
-                "@vendure/common": "^3.1.2",
+                "@vendure/common": "^3.1.3",
                 "faker": "^4.1.0",
                 "form-data": "^4.0.0",
                 "graphql": "~16.9.0",
@@ -33345,7 +33345,7 @@
                 "@types/mysql": "^2.15.26",
                 "@types/node-fetch": "^2.6.4",
                 "@types/pg": "^8.11.2",
-                "@vendure/core": "^3.1.2",
+                "@vendure/core": "^3.1.3",
                 "mysql": "^2.18.1",
                 "pg": "^8.11.3",
                 "rimraf": "^5.0.5",
@@ -33361,15 +33361,15 @@
         },
         "packages/ui-devkit": {
             "name": "@vendure/ui-devkit",
-            "version": "3.1.2",
+            "version": "3.1.3",
             "license": "GPL-3.0-or-later",
             "dependencies": {
                 "@angular-devkit/build-angular": "^17.2.3",
                 "@angular/cli": "^17.2.3",
                 "@angular/compiler": "^17.2.4",
                 "@angular/compiler-cli": "^17.2.4",
-                "@vendure/admin-ui": "^3.1.2",
-                "@vendure/common": "^3.1.2",
+                "@vendure/admin-ui": "^3.1.3",
+                "@vendure/common": "^3.1.3",
                 "chalk": "^4.1.0",
                 "chokidar": "^3.6.0",
                 "fs-extra": "^11.2.0",
@@ -33380,7 +33380,7 @@
                 "@rollup/plugin-node-resolve": "^15.2.3",
                 "@rollup/plugin-terser": "^0.4.4",
                 "@types/fs-extra": "^11.0.4",
-                "@vendure/core": "^3.1.2",
+                "@vendure/core": "^3.1.3",
                 "react": "^18.2.0",
                 "react-dom": "^18.2.0",
                 "rimraf": "^5.0.5",

+ 4 - 4
packages/admin-ui-plugin/package.json

@@ -1,6 +1,6 @@
 {
     "name": "@vendure/admin-ui-plugin",
-    "version": "3.1.2",
+    "version": "3.1.3",
     "main": "lib/index.js",
     "types": "lib/index.d.ts",
     "files": [
@@ -21,9 +21,9 @@
     "devDependencies": {
         "@types/express": "^4.17.21",
         "@types/fs-extra": "^11.0.4",
-        "@vendure/admin-ui": "^3.1.2",
-        "@vendure/common": "^3.1.2",
-        "@vendure/core": "^3.1.2",
+        "@vendure/admin-ui": "^3.1.3",
+        "@vendure/common": "^3.1.3",
+        "@vendure/core": "^3.1.3",
         "express": "^4.18.3",
         "rimraf": "^5.0.5",
         "typescript": "5.4.2"

+ 2 - 2
packages/admin-ui/package.json

@@ -1,6 +1,6 @@
 {
     "name": "@vendure/admin-ui",
-    "version": "3.1.2",
+    "version": "3.1.3",
     "license": "GPL-3.0-or-later",
     "scripts": {
         "ng": "ng",
@@ -49,7 +49,7 @@
         "@ng-select/ng-select": "^12.0.7",
         "@ngx-translate/core": "^15.0.0",
         "@ngx-translate/http-loader": "^8.0.0",
-        "@vendure/common": "^3.1.2",
+        "@vendure/common": "^3.1.3",
         "@webcomponents/custom-elements": "^1.6.0",
         "apollo-angular": "^6.0.0",
         "apollo-upload-client": "^18.0.1",

+ 1 - 1
packages/admin-ui/src/lib/core/src/common/version.ts

@@ -1,2 +1,2 @@
 // Auto-generated by the set-version.js script.
-export const ADMIN_UI_VERSION = '3.1.2';
+export const ADMIN_UI_VERSION = '3.1.3';

+ 5 - 8
packages/admin-ui/src/lib/order/src/components/draft-order-variant-selector/draft-order-variant-selector.component.html

@@ -39,14 +39,11 @@
             </button>
         </div>
         <ng-container *ngIf="orderLineCustomFields.length">
-            <div class="custom-field" *ngFor="let field of orderLineCustomFields">
-                <vdr-custom-field-control
-                    [compact]="true"
-                    [readonly]="false"
-                    [customField]="field"
-                    [customFieldsFormGroup]="customFieldsFormGroup"
-                ></vdr-custom-field-control>
-            </div>
+            <vdr-tabbed-custom-fields
+                entityName="Order"
+                [customFields]="orderLineCustomFields"
+                [customFieldsFormGroup]="customFieldsFormGroup"
+            ></vdr-tabbed-custom-fields>
         </ng-container>
     </div>
 </div>

+ 6 - 10
packages/admin-ui/src/lib/order/src/components/order-editor/order-editor.component.html

@@ -231,16 +231,12 @@
                             </div>
                         </div>
                     </div>
-                    <div class="form-grid" *ngIf="addItemSelectedVariant">
-                        <ng-container *ngFor="let customField of orderLineCustomFields">
-                            <vdr-custom-field-control
-                                [readonly]="!addItemSelectedVariant"
-                                [customField]="customField"
-                                [customFieldsFormGroup]="addItemCustomFieldsForm"
-                                entityName="OrderLine"
-                                [compact]="true"
-                            ></vdr-custom-field-control>
-                        </ng-container>
+                    <div *ngIf="addItemSelectedVariant">
+                        <vdr-tabbed-custom-fields
+                            entityName="Order"
+                            [customFields]="orderLineCustomFields"
+                            [customFieldsFormGroup]="addItemCustomFieldsForm"
+                        ></vdr-tabbed-custom-fields>
                     </div>
                 </div>
                 <div class="flex-spacer"></div>

+ 3 - 3
packages/asset-server-plugin/package.json

@@ -1,6 +1,6 @@
 {
     "name": "@vendure/asset-server-plugin",
-    "version": "3.1.2",
+    "version": "3.1.3",
     "main": "lib/index.js",
     "types": "lib/index.d.ts",
     "files": [
@@ -26,8 +26,8 @@
         "@types/express": "^4.17.21",
         "@types/fs-extra": "^11.0.4",
         "@types/node-fetch": "^2.6.11",
-        "@vendure/common": "^3.1.2",
-        "@vendure/core": "^3.1.2",
+        "@vendure/common": "^3.1.3",
+        "@vendure/core": "^3.1.3",
         "express": "^4.18.3",
         "node-fetch": "^2.7.0",
         "rimraf": "^5.0.5",

+ 3 - 3
packages/cli/package.json

@@ -1,6 +1,6 @@
 {
     "name": "@vendure/cli",
-    "version": "3.1.2",
+    "version": "3.1.3",
     "description": "A modern, headless ecommerce framework",
     "repository": {
         "type": "git",
@@ -35,7 +35,7 @@
     ],
     "dependencies": {
         "@clack/prompts": "^0.7.0",
-        "@vendure/common": "^3.1.2",
+        "@vendure/common": "^3.1.3",
         "change-case": "^4.1.2",
         "commander": "^11.0.0",
         "dotenv": "^16.4.5",
@@ -46,7 +46,7 @@
         "tsconfig-paths": "^4.2.0"
     },
     "devDependencies": {
-        "@vendure/core": "^3.1.2",
+        "@vendure/core": "^3.1.3",
         "typescript": "5.3.3"
     }
 }

+ 1 - 1
packages/common/package.json

@@ -1,6 +1,6 @@
 {
     "name": "@vendure/common",
-    "version": "3.1.2",
+    "version": "3.1.3",
     "main": "index.js",
     "license": "GPL-3.0-or-later",
     "scripts": {

+ 4 - 1
packages/core/e2e/cache-service-default.e2e-spec.ts

@@ -68,7 +68,10 @@ describe('CacheService with DefaultCachePlugin (sql)', () => {
 
     it('sets a key with ttl', () => setsAKeyWithTtl(cacheService, ttlProvider));
 
-    it('sets a key with sub-second ttl', () => setsAKeyWithSubSecondTtl(cacheService, ttlProvider));
+    // TODO: Re-enable this upon merging in the v3.2 changes. This test currently is flaky due to
+    // a missing precision on the CacheItem.expiresAt field. However, since the fix involves a minor
+    // breaking change, it is being held back until v3.2.
+    it.skip('sets a key with sub-second ttl', () => setsAKeyWithSubSecondTtl(cacheService, ttlProvider));
 
     it('evicts the oldest key when cache is full', () => evictsTheOldestKeyWhenCacheIsFull(cacheService));
 

+ 2 - 2
packages/core/package.json

@@ -1,6 +1,6 @@
 {
     "name": "@vendure/core",
-    "version": "3.1.2",
+    "version": "3.1.3",
     "description": "A modern, headless ecommerce framework",
     "repository": {
         "type": "git",
@@ -49,7 +49,7 @@
         "@nestjs/platform-express": "~10.4.12",
         "@nestjs/terminus": "~10.2.3",
         "@nestjs/typeorm": "~10.0.2",
-        "@vendure/common": "^3.1.2",
+        "@vendure/common": "^3.1.3",
         "bcrypt": "^5.1.1",
         "body-parser": "^1.20.2",
         "cookie-session": "^2.1.0",

+ 50 - 21
packages/core/src/api/common/graphql-value-transformer.ts

@@ -188,30 +188,56 @@ export class GraphqlValueTransformer {
         inputType: GraphQLInputObjectType,
         parent: TypeTreeNode,
     ): { [name: string]: TypeTreeNode } {
-        return Object.entries(inputType.getFields()).reduce((result, [key, field]) => {
-            const namedType = getNamedType(field.type);
-            if (namedType === parent.type) {
-                // prevent recursion-induced stack overflow
-                return result;
-            }
-            const child: TypeTreeNode = {
-                type: namedType,
-                isList: this.isList(field.type),
-                parent,
-                fragmentRefs: [],
-                children: {},
-            };
-            if (isInputObjectType(namedType)) {
-                child.children = this.getChildrenTreeNodes(namedType, child);
-            }
-            return { ...result, [key]: child };
-        }, {} as { [name: string]: TypeTreeNode });
+        return Object.entries(inputType.getFields()).reduce(
+            (result, [key, field]) => {
+                const namedType = getNamedType(field.type);
+                if (namedType === parent.type) {
+                    // prevent recursion-induced stack overflow
+                    return result;
+                }
+                const child: TypeTreeNode = {
+                    type: namedType,
+                    isList: this.isList(field.type),
+                    parent,
+                    fragmentRefs: [],
+                    children: {},
+                };
+                if (isInputObjectType(namedType)) {
+                    child.children = this.getChildrenTreeNodes(namedType, child);
+                }
+                return { ...result, [key]: child };
+            },
+            {} as { [name: string]: TypeTreeNode },
+        );
     }
 
     private isList(t: any): boolean {
         return isListType(t) || (isNonNullType(t) && isListType(t.ofType));
     }
 
+    private deepMergeChildren(
+        target: { [name: string]: TypeTreeNode },
+        source: { [name: string]: TypeTreeNode },
+    ): { [name: string]: TypeTreeNode } {
+        const merged = { ...target };
+        for (const key in source) {
+            if (source.hasOwnProperty(key)) {
+                if (merged[key]) {
+                    // If the key already exists, merge recursively
+                    if (source[key].children && Object.keys(source[key].children).length > 0) {
+                        merged[key].children = this.deepMergeChildren(
+                            merged[key].children,
+                            source[key].children,
+                        );
+                    }
+                } else {
+                    merged[key] = source[key];
+                }
+            }
+        }
+        return merged;
+    }
+
     private getTypeNodeByPath(typeTree: TypeTree, path: Array<string | number>): TypeTreeNode | undefined {
         let targetNode: TypeTreeNode | undefined = typeTree.operation;
         for (const segment of path) {
@@ -224,9 +250,12 @@ export class GraphqlValueTransformer {
                             const ref = fragmentRefs.pop();
                             if (ref) {
                                 const fragment = typeTree.fragments[ref];
-                                children = { ...children, ...fragment.children };
-                                if (fragment.fragmentRefs) {
-                                    fragmentRefs.push(...fragment.fragmentRefs);
+                                if (fragment) {
+                                    // Deeply merge the children
+                                    children = this.deepMergeChildren(children, fragment.children);
+                                    if (fragment.fragmentRefs) {
+                                        fragmentRefs.push(...fragment.fragmentRefs);
+                                    }
                                 }
                             }
                         }

+ 1 - 1
packages/core/src/api/config/configure-graphql-module.ts

@@ -160,7 +160,7 @@ async function createGraphQLOptions(
             .forEach(documentNode => (schema = extendSchema(schema, documentNode)));
         schema = generateListOptions(schema);
         schema = addGraphQLCustomFields(schema, customFields, apiType === 'shop');
-        schema = addOrderLineCustomFieldsInput(schema, customFields.OrderLine || []);
+        schema = addOrderLineCustomFieldsInput(schema, customFields.OrderLine || [], apiType === 'shop');
         schema = addModifyOrderCustomFields(schema, customFields.Order || []);
         schema = addShippingMethodQuoteCustomFields(schema, customFields.ShippingMethod || []);
         schema = addPaymentMethodQuoteCustomFields(schema, customFields.PaymentMethod || []);

+ 5 - 2
packages/core/src/api/config/graphql-custom-fields.ts

@@ -394,10 +394,13 @@ export function addModifyOrderCustomFields(
 export function addOrderLineCustomFieldsInput(
     typeDefsOrSchema: string | GraphQLSchema,
     orderLineCustomFields: CustomFieldConfig[],
+    publicOnly: boolean,
 ): GraphQLSchema {
     const schema = typeof typeDefsOrSchema === 'string' ? buildSchema(typeDefsOrSchema) : typeDefsOrSchema;
+    orderLineCustomFields = orderLineCustomFields.filter(f => f.internal !== true);
     const publicCustomFields = orderLineCustomFields.filter(f => f.public !== false);
-    if (!publicCustomFields || publicCustomFields.length === 0) {
+    const customFields = publicOnly ? publicCustomFields : orderLineCustomFields;
+    if (!customFields || customFields.length === 0) {
         return schema;
     }
     const schemaConfig = schema.toConfig();
@@ -428,7 +431,7 @@ export function addOrderLineCustomFieldsInput(
     }
     const input = new GraphQLInputObjectType({
         name: 'OrderLineCustomFieldsInput',
-        fields: publicCustomFields.reduce((fields, field) => {
+        fields: customFields.reduce((fields, field) => {
             const name = getGraphQlInputName(field);
             const inputTypeName = getGraphQlInputType('OrderLine')(field);
             // eslint-disable-next-line @typescript-eslint/no-non-null-assertion

+ 10 - 1
packages/core/src/plugin/default-job-queue-plugin/sql-job-buffer-storage-strategy.ts

@@ -73,8 +73,17 @@ export class SqlJobBufferStorageStrategy implements JobBufferStorageStrategy {
 
     private toJobConfig(job: Job<any>): JobConfig<any> {
         return {
-            ...job,
+            queueName: job.queueName,
             data: job.data,
+            retries: job.retries,
+            attempts: job.attempts,
+            state: job.state,
+            progress: job.progress,
+            result: job.result,
+            error: job.error,
+            createdAt: job.createdAt,
+            startedAt: job.startedAt,
+            settledAt: job.settledAt,
             id: job.id ?? undefined,
         };
     }

+ 102 - 54
packages/core/src/service/services/collection.service.ts

@@ -7,6 +7,7 @@ import {
     DeletionResponse,
     DeletionResult,
     JobState,
+    LanguageCode,
     MoveCollectionInput,
     Permission,
     PreviewCollectionVariantsInput,
@@ -18,17 +19,12 @@ import { ROOT_COLLECTION_NAME } from '@vendure/common/lib/shared-constants';
 import { ID, PaginatedList } from '@vendure/common/lib/shared-types';
 import { unique } from '@vendure/common/lib/unique';
 import { merge } from 'rxjs';
-import { debounceTime } from 'rxjs/operators';
+import { debounceTime, filter } from 'rxjs/operators';
 import { In, IsNull } from 'typeorm';
 
-import { RequestContext, SerializedRequestContext } from '../../api/common/request-context';
+import { RequestContext } from '../../api/common/request-context';
 import { RelationPaths } from '../../api/decorators/relations.decorator';
-import {
-    ForbiddenError,
-    IllegalOperationError,
-    InternalServerError,
-    UserInputError,
-} from '../../common/error/errors';
+import { ForbiddenError, IllegalOperationError, UserInputError } from '../../common/error/errors';
 import { ListQueryOptions } from '../../common/types/common-types';
 import { Translated } from '../../common/types/locale-types';
 import { assertFound, idsAreEqual } from '../../common/utils';
@@ -48,6 +44,7 @@ import { JobQueueService } from '../../job-queue/job-queue.service';
 import { ConfigArgService } from '../helpers/config-arg/config-arg.service';
 import { CustomFieldRelationService } from '../helpers/custom-field-relation/custom-field-relation.service';
 import { ListQueryBuilder } from '../helpers/list-query-builder/list-query-builder';
+import { RequestContextService } from '../helpers/request-context/request-context.service';
 import { SlugValidator } from '../helpers/slug-validator/slug-validator';
 import { TranslatableSaver } from '../helpers/translatable-saver/translatable-saver';
 import { TranslatorService } from '../helpers/translator/translator.service';
@@ -58,7 +55,14 @@ import { ChannelService } from './channel.service';
 import { RoleService } from './role.service';
 
 export type ApplyCollectionFiltersJobData = {
-    ctx: SerializedRequestContext;
+    // We store this channel data inside a `ctx` object for backward-compatible reasons
+    // since there is a chance that some external plugins assume the existence of a `ctx`
+    // property on this payload. Notably, the AdvancedSearchPlugin defines its own
+    // CollectionJobBuffer which makes this assumption.
+    ctx: {
+        channelToken: string;
+        languageCode: LanguageCode;
+    };
     collectionIds: ID[];
     applyToChangedVariantsOnly?: boolean;
 };
@@ -73,6 +77,7 @@ export type ApplyCollectionFiltersJobData = {
 export class CollectionService implements OnModuleInit {
     private rootCollection: Translated<Collection> | undefined;
     private applyFiltersQueue: JobQueue<ApplyCollectionFiltersJobData>;
+    private applyAllFiltersOnProductUpdates = true;
 
     constructor(
         private connection: TransactionalConnection,
@@ -88,6 +93,7 @@ export class CollectionService implements OnModuleInit {
         private customFieldRelationService: CustomFieldRelationService,
         private translator: TranslatorService,
         private roleService: RoleService,
+        private requestContextService: RequestContextService,
     ) {}
 
     /**
@@ -98,32 +104,45 @@ export class CollectionService implements OnModuleInit {
         const variantEvents$ = this.eventBus.ofType(ProductVariantEvent);
 
         merge(productEvents$, variantEvents$)
-            .pipe(debounceTime(50))
+            .pipe(
+                filter(() => {
+                    if (!this.applyAllFiltersOnProductUpdates) {
+                        Logger.debug(
+                            `Detected product data change, but skipping applyCollectionFilters because applyAllFiltersOnProductUpdates = false`,
+                        );
+                        return false;
+                    } else {
+                        return true;
+                    }
+                }),
+                debounceTime(50),
+            )
             // eslint-disable-next-line @typescript-eslint/no-misused-promises
             .subscribe(async event => {
-                const collections = await this.connection.rawConnection
-                    .getRepository(Collection)
-                    .createQueryBuilder('collection')
-                    .select('collection.id', 'id')
-                    .getRawMany();
-                await this.applyFiltersQueue.add(
-                    {
-                        ctx: event.ctx.serialize(),
-                        collectionIds: collections.map(c => c.id),
-                        applyToChangedVariantsOnly: true,
-                    },
-                    { ctx: event.ctx },
-                );
+                await this.triggerApplyFiltersJob(event.ctx);
             });
 
         this.applyFiltersQueue = await this.jobQueueService.createQueue({
             name: 'apply-collection-filters',
             process: async job => {
-                const ctx = RequestContext.deserialize(job.data.ctx);
-
-                Logger.verbose(`Processing ${job.data.collectionIds.length} Collections`);
+                const ctx = await this.requestContextService.create({
+                    apiType: 'admin',
+                    languageCode: job.data.ctx.languageCode,
+                    channelOrToken: job.data.ctx.channelToken,
+                });
+                let collectionIds = job.data.collectionIds;
+                if (collectionIds.length === 0) {
+                    // An empty array means that all collections should be updated
+                    const collections = await this.connection.rawConnection
+                        .getRepository(Collection)
+                        .createQueryBuilder('collection')
+                        .select('collection.id', 'id')
+                        .getRawMany();
+                    collectionIds = collections.map(c => c.id);
+                }
+                Logger.verbose(`Processing ${collectionIds.length} Collections`);
                 let completed = 0;
-                for (const collectionId of job.data.collectionIds) {
+                for (const collectionId of collectionIds) {
                     if (job.state === JobState.CANCELLED) {
                         throw new Error(`Job was cancelled`);
                     }
@@ -164,6 +183,7 @@ export class CollectionService implements OnModuleInit {
                         }
                     }
                 }
+                return { processedCollections: completed };
             },
         });
     }
@@ -303,7 +323,7 @@ export class CollectionService implements OnModuleInit {
     async getBreadcrumbs(
         ctx: RequestContext,
         collection: Collection,
-    ): Promise<Array<{ name: string; id: ID, slug: string }>> {
+    ): Promise<Array<{ name: string; id: ID; slug: string }>> {
         const rootCollection = await this.getRootCollection(ctx);
         if (idsAreEqual(collection.id, rootCollection.id)) {
             return [pick(rootCollection, ['id', 'name', 'slug'])];
@@ -480,13 +500,9 @@ export class CollectionService implements OnModuleInit {
             input,
             collection,
         );
-        await this.applyFiltersQueue.add(
-            {
-                ctx: ctx.serialize(),
-                collectionIds: [collection.id],
-            },
-            { ctx },
-        );
+        await this.triggerApplyFiltersJob(ctx, {
+            collectionIds: [collection.id],
+        });
         await this.eventBus.publish(new CollectionEvent(ctx, collectionWithRelations, 'created', input));
         return assertFound(this.findOne(ctx, collection.id));
     }
@@ -508,14 +524,10 @@ export class CollectionService implements OnModuleInit {
         });
         await this.customFieldRelationService.updateRelations(ctx, Collection, input, collection);
         if (input.filters) {
-            await this.applyFiltersQueue.add(
-                {
-                    ctx: ctx.serialize(),
-                    collectionIds: [collection.id],
-                    applyToChangedVariantsOnly: false,
-                },
-                { ctx },
-            );
+            await this.triggerApplyFiltersJob(ctx, {
+                collectionIds: [collection.id],
+                applyToChangedVariantsOnly: false,
+            });
         } else {
             const affectedVariantIds = await this.getCollectionProductVariantIds(collection);
             await this.eventBus.publish(new CollectionModificationEvent(ctx, collection, affectedVariantIds));
@@ -586,14 +598,55 @@ export class CollectionService implements OnModuleInit {
         siblings = moveToIndex(input.index, target, siblings);
 
         await this.connection.getRepository(ctx, Collection).save(siblings);
+        await this.triggerApplyFiltersJob(ctx, {
+            collectionIds: [target.id],
+        });
+        return assertFound(this.findOne(ctx, input.collectionId));
+    }
+
+    /**
+     * @description
+     * By default, whenever product data is updated (as determined by subscribing to the
+     * {@link ProductEvent} and {@link ProductVariantEvent} events), the CollectionFilters are re-applied
+     * to all Collections.
+     *
+     * In certain scenarios, such as when a large number of products are updated at once due to
+     * bulk data import, this can be inefficient. In such cases, you can disable this behaviour
+     * for the duration of the import process by calling this method with `false`, and then
+     * re-enable it by calling with `true`.
+     *
+     * Afterward, you can call the `triggerApplyFiltersJob` method to manually re-apply the filters.
+     *
+     * @since 3.1.3
+     */
+    setApplyAllFiltersOnProductUpdates(applyAllFiltersOnProductUpdates: boolean) {
+        this.applyAllFiltersOnProductUpdates = applyAllFiltersOnProductUpdates;
+    }
+
+    /**
+     * @description
+     * Triggers the creation of an `apply-collection-filters` job which will cause the contents
+     * of the specified collections to be re-evaluated against their filters.
+     *
+     * If no `collectionIds` option is passed, then all collections will be re-evaluated.
+     *
+     * @since 3.1.3
+     */
+    async triggerApplyFiltersJob(
+        ctx: RequestContext,
+        options?: { collectionIds?: ID[]; applyToChangedVariantsOnly?: boolean },
+    ) {
         await this.applyFiltersQueue.add(
             {
-                ctx: ctx.serialize(),
-                collectionIds: [target.id],
+                ctx: {
+                    languageCode: ctx.languageCode,
+                    channelToken: ctx.channel.token,
+                },
+                applyToChangedVariantsOnly: options?.applyToChangedVariantsOnly,
+                collectionIds: options?.collectionIds ?? [],
             },
             { ctx },
         );
-        return assertFound(this.findOne(ctx, input.collectionId));
     }
 
     private getCollectionFiltersFromInput(
@@ -876,14 +929,9 @@ export class CollectionService implements OnModuleInit {
             ([] as ID[]).concat(...collectionsToAssign.map(c => c.assets.map(a => a.assetId))),
         );
         await this.assetService.assignToChannel(ctx, { channelId: input.channelId, assetIds });
-
-        await this.applyFiltersQueue.add(
-            {
-                ctx: ctx.serialize(),
-                collectionIds: collectionsToAssign.map(collection => collection.id),
-            },
-            { ctx },
-        );
+        await this.triggerApplyFiltersJob(ctx, {
+            collectionIds: collectionsToAssign.map(collection => collection.id),
+        });
 
         return this.connection
             .findByIdsInChannel(

+ 3 - 3
packages/create/package.json

@@ -1,6 +1,6 @@
 {
     "name": "@vendure/create",
-    "version": "3.1.2",
+    "version": "3.1.3",
     "license": "GPL-3.0-or-later",
     "bin": {
         "create": "./index.js"
@@ -27,14 +27,14 @@
         "@types/fs-extra": "^11.0.4",
         "@types/handlebars": "^4.1.0",
         "@types/semver": "^7.5.8",
-        "@vendure/core": "^3.1.2",
+        "@vendure/core": "^3.1.3",
         "rimraf": "^5.0.5",
         "ts-node": "^10.9.2",
         "typescript": "5.3.3"
     },
     "dependencies": {
         "@clack/prompts": "^0.7.0",
-        "@vendure/common": "^3.1.2",
+        "@vendure/common": "^3.1.3",
         "commander": "^11.0.0",
         "cross-spawn": "^7.0.3",
         "fs-extra": "^11.2.0",

+ 3 - 2
packages/dev-server/index.ts

@@ -1,11 +1,12 @@
-import { bootstrap, JobQueueService } from '@vendure/core';
+import { bootstrap, JobQueueService, runMigrations } from '@vendure/core';
 
 import { devConfig } from './dev-config';
 
 /**
  * This bootstraps the dev server, used for testing Vendure during development.
  */
-bootstrap(devConfig)
+runMigrations(devConfig)
+    .then(() => bootstrap(devConfig))
     .then(app => {
         if (process.env.RUN_JOB_QUEUE === '1') {
             return app.get(JobQueueService).start();

+ 9 - 9
packages/dev-server/package.json

@@ -1,6 +1,6 @@
 {
     "name": "dev-server",
-    "version": "3.1.2",
+    "version": "3.1.3",
     "main": "index.js",
     "license": "GPL-3.0-or-later",
     "private": true,
@@ -15,17 +15,17 @@
     },
     "dependencies": {
         "@nestjs/axios": "^3.0.2",
-        "@vendure/admin-ui-plugin": "^3.1.2",
-        "@vendure/asset-server-plugin": "^3.1.2",
-        "@vendure/common": "^3.1.2",
-        "@vendure/core": "^3.1.2",
-        "@vendure/elasticsearch-plugin": "^3.1.2",
-        "@vendure/email-plugin": "^3.1.2",
+        "@vendure/admin-ui-plugin": "^3.1.3",
+        "@vendure/asset-server-plugin": "^3.1.3",
+        "@vendure/common": "^3.1.3",
+        "@vendure/core": "^3.1.3",
+        "@vendure/elasticsearch-plugin": "^3.1.3",
+        "@vendure/email-plugin": "^3.1.3",
         "typescript": "5.3.3"
     },
     "devDependencies": {
-        "@vendure/testing": "^3.1.2",
-        "@vendure/ui-devkit": "^3.1.2",
+        "@vendure/testing": "^3.1.3",
+        "@vendure/ui-devkit": "^3.1.3",
         "commander": "^12.0.0",
         "concurrently": "^8.2.2",
         "csv-stringify": "^6.4.6",

+ 3 - 3
packages/elasticsearch-plugin/package.json

@@ -1,6 +1,6 @@
 {
     "name": "@vendure/elasticsearch-plugin",
-    "version": "3.1.2",
+    "version": "3.1.3",
     "license": "GPL-3.0-or-later",
     "main": "lib/index.js",
     "types": "lib/index.d.ts",
@@ -26,8 +26,8 @@
         "fast-deep-equal": "^3.1.3"
     },
     "devDependencies": {
-        "@vendure/common": "^3.1.2",
-        "@vendure/core": "^3.1.2",
+        "@vendure/common": "^3.1.3",
+        "@vendure/core": "^3.1.3",
         "rimraf": "^5.0.5",
         "typescript": "5.3.3"
     }

+ 3 - 3
packages/email-plugin/package.json

@@ -1,6 +1,6 @@
 {
     "name": "@vendure/email-plugin",
-    "version": "3.1.2",
+    "version": "3.1.3",
     "license": "GPL-3.0-or-later",
     "main": "lib/index.js",
     "types": "lib/index.d.ts",
@@ -34,8 +34,8 @@
         "@types/express": "^4.17.21",
         "@types/fs-extra": "^11.0.4",
         "@types/mjml": "^4.7.4",
-        "@vendure/common": "^3.1.2",
-        "@vendure/core": "^3.1.2",
+        "@vendure/common": "^3.1.3",
+        "@vendure/core": "^3.1.3",
         "rimraf": "^5.0.5",
         "typescript": "5.3.3"
     }

+ 3 - 3
packages/harden-plugin/package.json

@@ -1,6 +1,6 @@
 {
     "name": "@vendure/harden-plugin",
-    "version": "3.1.2",
+    "version": "3.1.3",
     "license": "GPL-3.0-or-later",
     "main": "lib/index.js",
     "types": "lib/index.d.ts",
@@ -21,7 +21,7 @@
         "graphql-query-complexity": "^0.12.0"
     },
     "devDependencies": {
-        "@vendure/common": "^3.1.2",
-        "@vendure/core": "^3.1.2"
+        "@vendure/common": "^3.1.3",
+        "@vendure/core": "^3.1.3"
     }
 }

+ 3 - 3
packages/job-queue-plugin/package.json

@@ -1,6 +1,6 @@
 {
     "name": "@vendure/job-queue-plugin",
-    "version": "3.1.2",
+    "version": "3.1.3",
     "license": "GPL-3.0-or-later",
     "main": "package/index.js",
     "types": "package/index.d.ts",
@@ -23,8 +23,8 @@
     },
     "devDependencies": {
         "@google-cloud/pubsub": "^2.8.0",
-        "@vendure/common": "^3.1.2",
-        "@vendure/core": "^3.1.2",
+        "@vendure/common": "^3.1.3",
+        "@vendure/core": "^3.1.3",
         "bullmq": "^5.4.2",
         "ioredis": "^5.3.2",
         "rimraf": "^5.0.5",

+ 10 - 1
packages/job-queue-plugin/src/bullmq/redis-job-buffer-storage-strategy.ts

@@ -54,8 +54,17 @@ export class RedisJobBufferStorageStrategy implements JobBufferStorageStrategy {
 
     private toJobConfigString(job: Job<any>): string {
         const jobConfig: JobConfig<any> = {
-            ...job,
+            queueName: job.queueName,
             data: job.data,
+            retries: job.retries,
+            attempts: job.attempts,
+            state: job.state,
+            progress: job.progress,
+            result: job.result,
+            error: job.error,
+            createdAt: job.createdAt,
+            startedAt: job.startedAt,
+            settledAt: job.settledAt,
             id: job.id ?? undefined,
         };
         return JSON.stringify(jobConfig);

+ 4 - 4
packages/payments-plugin/package.json

@@ -1,6 +1,6 @@
 {
     "name": "@vendure/payments-plugin",
-    "version": "3.1.2",
+    "version": "3.1.3",
     "license": "GPL-3.0-or-later",
     "main": "package/index.js",
     "types": "package/index.d.ts",
@@ -46,9 +46,9 @@
         "@mollie/api-client": "^3.7.0",
         "@types/braintree": "^3.3.11",
         "@types/localtunnel": "2.0.4",
-        "@vendure/common": "^3.1.2",
-        "@vendure/core": "^3.1.2",
-        "@vendure/testing": "^3.1.2",
+        "@vendure/common": "^3.1.3",
+        "@vendure/core": "^3.1.3",
+        "@vendure/testing": "^3.1.3",
         "braintree": "^3.22.0",
         "localtunnel": "2.0.2",
         "nock": "^13.1.4",

+ 3 - 3
packages/sentry-plugin/package.json

@@ -1,6 +1,6 @@
 {
     "name": "@vendure/sentry-plugin",
-    "version": "3.1.2",
+    "version": "3.1.3",
     "license": "GPL-3.0-or-later",
     "main": "lib/index.js",
     "types": "lib/index.d.ts",
@@ -22,7 +22,7 @@
     },
     "devDependencies": {
         "@sentry/node": "^7.106.1",
-        "@vendure/common": "^3.1.2",
-        "@vendure/core": "^3.1.2"
+        "@vendure/common": "^3.1.3",
+        "@vendure/core": "^3.1.3"
     }
 }

+ 3 - 3
packages/stellate-plugin/package.json

@@ -1,6 +1,6 @@
 {
     "name": "@vendure/stellate-plugin",
-    "version": "3.1.2",
+    "version": "3.1.3",
     "license": "GPL-3.0-or-later",
     "main": "lib/index.js",
     "types": "lib/index.d.ts",
@@ -21,7 +21,7 @@
         "node-fetch": "^2.7.0"
     },
     "devDependencies": {
-        "@vendure/common": "^3.1.2",
-        "@vendure/core": "^3.1.2"
+        "@vendure/common": "^3.1.3",
+        "@vendure/core": "^3.1.3"
     }
 }

+ 3 - 3
packages/testing/package.json

@@ -1,6 +1,6 @@
 {
     "name": "@vendure/testing",
-    "version": "3.1.2",
+    "version": "3.1.3",
     "description": "End-to-end testing tools for Vendure projects",
     "keywords": [
         "vendure",
@@ -38,7 +38,7 @@
     },
     "dependencies": {
         "@graphql-typed-document-node/core": "^3.2.0",
-        "@vendure/common": "^3.1.2",
+        "@vendure/common": "^3.1.3",
         "faker": "^4.1.0",
         "form-data": "^4.0.0",
         "graphql": "~16.9.0",
@@ -51,7 +51,7 @@
         "@types/mysql": "^2.15.26",
         "@types/node-fetch": "^2.6.4",
         "@types/pg": "^8.11.2",
-        "@vendure/core": "^3.1.2",
+        "@vendure/core": "^3.1.3",
         "mysql": "^2.18.1",
         "pg": "^8.11.3",
         "rimraf": "^5.0.5",

+ 4 - 4
packages/ui-devkit/package.json

@@ -1,6 +1,6 @@
 {
     "name": "@vendure/ui-devkit",
-    "version": "3.1.2",
+    "version": "3.1.3",
     "description": "A library for authoring Vendure Admin UI extensions",
     "keywords": [
         "vendure",
@@ -40,8 +40,8 @@
         "@angular/cli": "^17.2.3",
         "@angular/compiler": "^17.2.4",
         "@angular/compiler-cli": "^17.2.4",
-        "@vendure/admin-ui": "^3.1.2",
-        "@vendure/common": "^3.1.2",
+        "@vendure/admin-ui": "^3.1.3",
+        "@vendure/common": "^3.1.3",
         "chalk": "^4.1.0",
         "chokidar": "^3.6.0",
         "fs-extra": "^11.2.0",
@@ -52,7 +52,7 @@
         "@rollup/plugin-node-resolve": "^15.2.3",
         "@rollup/plugin-terser": "^0.4.4",
         "@types/fs-extra": "^11.0.4",
-        "@vendure/core": "^3.1.2",
+        "@vendure/core": "^3.1.3",
         "react": "^18.2.0",
         "react-dom": "^18.2.0",
         "rimraf": "^5.0.5",