@render-lab/tasks-shopify
v0.1.2
Published
Durable Shopify tasks for Render Workflows: shopify.getOrder/listOrders/fulfillOrder/updateInventory.
Downloads
204
Readme
@render-lab/tasks-shopify
⚠️ Experimental: proof of concept. This package is part of the Render Tasks POC and is published for testing only. It is not fully tested or production ready. Task names, inputs, outputs, and behavior can change or break in any release. Pin exact versions and expect breaking changes.
Durable Shopify tasks for Render Workflows.
import {
getOrder,
listOrders,
fulfillOrder,
refundOrder,
cancelOrder,
updateInventory,
getProduct,
listProducts,
createProduct,
updateProduct,
getCustomer,
searchCustomers,
} from "@render-lab/tasks-shopify";| Task | Input | Output |
| ------------------------- | ---------------------------------------------- | ----------------------- |
| shopify.getOrder | { orderId } | Order |
| shopify.listOrders | { status?, limit? } | Order[] |
| shopify.fulfillOrder | { orderId, trackingNumber? } | FulfillResult |
| shopify.refundOrder | { orderId, amount? } | RefundResult |
| shopify.cancelOrder | { orderId, reason? } | Order |
| shopify.updateInventory | { inventoryItemId, locationId, delta } | UpdateInventoryResult |
| shopify.getProduct | { productId } | Product |
| shopify.listProducts | { limit? } | Product[] |
| shopify.createProduct | { title, status?, handle?, variants? } | Product |
| shopify.updateProduct | { productId, title?, status?, handle?, variants? } | Product |
| shopify.getCustomer | { customerId } | Customer |
| shopify.searchCustomers | { query, limit? } | Customer[] |
listOrders defaults status to "any" and limit to 20; listProducts and searchCustomers default limit to 20.
All tasks return JSON-serializable DTOs (Order, OrderLineItem, FulfillResult, RefundResult, UpdateInventoryResult, Product, ProductVariant, Customer) — never raw Shopify API responses. Single resources are unwrapped from Shopify's { product: … } / { customer: … } envelope and lists from { products: [ … ] } / { customers: [ … ] }. The default port is fetch-backed against the Shopify Admin REST API at https://<store>/admin/api/2024-10, authenticated with the X-Shopify-Access-Token header.
Webhook adapter
Use @render-lab/tasks-shopify/webhooks from a trigger web service to verify Shopify webhooks and map verified events to Workflow task runs:
import { shopifyAdapter } from "@render-lab/tasks-shopify/webhooks";
import { serveDispatchServer } from "@render-lab/triggers";
serveDispatchServer({
webhooks: {
shopify: shopifyAdapter({
onEvent: ({ topic, payload }) => {
if (topic !== "orders/create") return null;
if (typeof payload.id !== "number") return null;
return { task: "fulfillment.run", args: [{ orderId: payload.id }] };
},
}),
},
});Shopify signs the raw body with X-Shopify-Hmac-Sha256 = BASE64(HMAC-SHA256(secret, rawBody)) (base64, not hex), which verify checks in constant time; map reads the event type from the X-Shopify-Topic header (e.g. orders/create). The /webhooks subpath does not import the package root, register shopify.* tasks, or read credentials at import time (the secret is read inside verify). Keep provider event mapping in the trigger service because task names are workflow-specific.
Install
pnpm add @render-lab/tasks-shopify @renderinc/sdk@renderinc/sdk is a peer dependency. The package has no vendor dependency — it uses the global fetch.
If you use the webhook adapter in a trigger web service, also install @render-lab/triggers.
Environment contract
Credentials are read lazily at the first API call, never at import (ADR-0007), so importing the package for one task never requires another's secret.
| Variable | Required | Purpose |
| ---------------------- | -------- | ------------------------------------------------------------------------- |
| SHOPIFY_STORE | yes | Store domain used as the API host, e.g. acme.myshopify.com. |
| SHOPIFY_ACCESS_TOKEN | yes | Admin API access token, sent as X-Shopify-Access-Token: …. |
| SHOPIFY_WEBHOOK_SECRET | for the Shopify webhook adapter | HMAC secret used by @render-lab/tasks-shopify/webhooks to verify X-Shopify-Hmac-Sha256 before dispatch. This belongs on the trigger web service, not the Workflow service. |
Extending & testing
Every operation exports the wrapped task and its raw *Impl. The impls depend on a small ShopifyPort interface, so they unit-test without touching the network:
import { getOrderImpl, type ShopifyPort } from "@render-lab/tasks-shopify";
const shopify: Partial<ShopifyPort> = {
getOrder: async () => ({
id: "450789469",
name: "#1001",
email: "[email protected]",
financialStatus: "paid",
fulfillmentStatus: null,
totalPrice: "199.00",
currency: "USD",
lineItems: [{ id: "li-1", title: "Widget", quantity: 2, sku: "AW-01" }],
}),
};
await getOrderImpl({ orderId: "450789469" }, { shopify } as any);Run the tests with pnpm -C packages/tasks-shopify test.
