bluestone-commercetools
Keeps a commercetools catalog in step with Bluestone PIM, by syncing the categories, products, variants and related products that changed after each Bluestone publish.
When to use
Use it when a shop on @evolve-framework/commercetools gets its product data
from Bluestone PIM. The package writes to commercetools:
- Categories: the subtree under
BLUESTONE_CATEGORY_WEBSHOP_ID, with the category custom typeCOMMERCETOOLS_CATEGORY_TYPE_KEY. - Products and variants: keyed by the Bluestone product number, with a
product type from
BLUESTONE_PRODUCT_TYPE_MAPPINGand the tax categoryCOMMERCETOOLS_TAX_CATEGORY_KEY. Products are published. - Specifications: the Bluestone attributes of each variant, as a custom
object in the
COMMERCETOOLS_PRODUCT_SPECIFICATIONS_CONTAINERcontainer. - Related products: the
related-productsattribute.
The commercetools project must already have the category custom type, the
product types and the tax category. The product types need the variant
attributes syncId, syncDate, specifications and related-products, and
the category type needs the fields syncId and syncDate. Every product must
be in a category that BLUESTONE_PRODUCT_TYPE_MAPPING maps to a product type.
A shop on Medusa uses @evolve-framework/medusa-plugin-bluestone instead.
Get started
Install the package. It comes from the Evolve registry, which needs a one-time sign-in.
pnpm add @evolve-framework/bluestone-commercetools
For example:
import { createSyncContext } from "@evolve-framework/bluestone-commercetools";import { BluestoneCommercetoolsConfig } from "@evolve-framework/bluestone-commercetools/config";import { handleProductSyncDone } from "@evolve-framework/bluestone-commercetools/events/product-sync-done";import { webhookPayloadSchema } from "@evolve-framework/bluestone-commercetools/messages";import { BluestoneCommercetoolsModule } from "@evolve-framework/bluestone-commercetools/module";import { createSQSHandler, SqsPublisher } from "@evolve-framework/cloud-adapter-aws";import { createApplication } from "@evolve-framework/core";
const config = await BluestoneCommercetoolsConfig.load();
// The web service: it checks Bluestone's webhook and queues the payload.const publisher = new SqsPublisher(config.BLUESTONE_WEBHOOK_TARGET);
const app = await createApplication({ name: "bluestone-commercetools", module: new BluestoneCommercetoolsModule({ config: { webhookSecret: config.BLUESTONE_WEBHOOK_SECRET, validateSignature: config.BLUESTONE_WEBHOOK_VALIDATE_SIGNATURE, }, publishMessage: (payload) => publisher.publish(payload), }), http: { address: { host: "0.0.0.0", port: 8080 } },});await app.start();
// The queue consumer, usually a separate function: it runs the sync.const ctx = await createSyncContext(config);
export const handler = createSQSHandler( (payload) => handleProductSyncDone(ctx, payload), (message) => webhookPayloadSchema.parse(message),);Modules
BluestoneCommercetoolsModule
The HTTP module that receives Bluestone's webhook.
POST /product-sync-doneverifies the signature and the payload, passes the payload topublishMessageand answers201. It answers401for a bad signature or payload, and500whenpublishMessagethrows.GET /healthcheckanswers200with the component name.
It does not run the sync: a queue consumer does that with
handleProductSyncDone, so Bluestone gets its answer at once.
import { BluestoneCommercetoolsModule } from "@evolve-framework/bluestone-commercetools";new BluestoneCommercetoolsModule(options: BluestoneCommercetoolsModuleOptions)| Option | Type | Description |
|---|---|---|
config | BluestoneCommercetoolsModuleConfig | How the webhook checks its calls, and what the healthcheck reports. |
publishMessage | (payload: { timestamp: number; events: { changes: { eventType: "PRODUCT_SYNC_DONE"; entityIds: string[]; syncDoneData: { field: string; value: string; context: … | Called with the payload once its signature and shape are valid. It usually
publishes to a queue, with a |
BluestoneCommercetoolsModuleConfig3The fields of config.
| Field | Type | Description |
|---|---|---|
webhookSecret | string | HMAC-SHA256 secret used to verify the |
validateSignature? | boolean | Whether to verify the |
componentName? | string | Reported by |
Extends AbstractModule<unknown>.
Testing
Test helpers in /testing. What they are for
Entry points
@evolve-framework/bluestone-commercetools | Everything below except ./testing, plus SyncContext and createSyncContext14 exports |
@evolve-framework/bluestone-commercetools/client | BluestonePimClient and createBluestonePimClient, the Bluestone PIM API client, which retries when it is rate limited2 exports |
@evolve-framework/bluestone-commercetools/commercetools | createCtClient, the commercetools request builder for the sync1 export |
@evolve-framework/bluestone-commercetools/config | BluestoneCommercetoolsConfig, the environment configuration that a service loads or extends1 export |
@evolve-framework/bluestone-commercetools/core/sync | sync, which applies one Bluestone sync to commercetools1 export |
@evolve-framework/bluestone-commercetools/events/product-sync-done | handleProductSyncDone, the queue consumer for a webhook payload1 export |
@evolve-framework/bluestone-commercetools/messages | webhookPayloadSchema and the webhook payload types3 exports |
@evolve-framework/bluestone-commercetools/module | BluestoneCommercetoolsModule, the HTTP module with POST /product-sync-done and GET /healthcheck, and its option types2 exports |
@evolve-framework/bluestone-commercetools/processes/full | fullSync, which copies the complete webshop tree1 export |
@evolve-framework/bluestone-commercetools/testing | Fixtures for Bluestone and commercetools data, and an MSW server with the mocked commercetools project142 exports |

