docs: fixes to type errors in guides (#13797)

This commit is contained in:
Shahed Nasser
2025-10-21 16:12:35 +03:00
committed by GitHub
parent d9249be6e6
commit 0d83918348
19 changed files with 922 additions and 682 deletions
@@ -197,7 +197,7 @@ export default class AgenticCommerceService {
// ...
async verifySignature({
signature,
payload
payload,
}: {
// base64 encoded signature
signature: string
@@ -205,18 +205,18 @@ export default class AgenticCommerceService {
}) {
try {
// Decode the base64 signature
const receivedSignature = Buffer.from(signature, 'base64')
const receivedSignature = Buffer.from(signature, "base64")
// Create HMAC-SHA256 signature using your signing key
const expectedSignature = crypto
.createHmac('sha256', this.options.signatureKey)
.update(JSON.stringify(payload), 'utf8')
.createHmac("sha256", this.options.signatureKey)
.update(JSON.stringify(payload), "utf8")
.digest()
// Compare signatures using constant-time comparison to prevent timing attacks
return crypto.timingSafeEqual(receivedSignature, expectedSignature)
} catch (error) {
console.error('Signature verification failed:', error)
console.error("Signature verification failed:", error)
return false
}
}
@@ -237,8 +237,8 @@ Add the following method to the `AgenticCommerceService` class:
export default class AgenticCommerceService {
// ...
async getSignature(data: any) {
return Buffer.from(crypto.createHmac('sha256', this.options.signatureKey)
.update(JSON.stringify(data), 'utf8').digest()).toString('base64')
return Buffer.from(crypto.createHmac("sha256", this.options.signatureKey)
.update(JSON.stringify(data), "utf8").digest()).toString("base64")
}
}
```
@@ -276,7 +276,7 @@ export default class AgenticCommerceService {
// ...
async sendWebhookEvent({
type,
data
data,
}: AgenticCommerceWebhookEvent) {
// Create signature
const signature = this.getSignature(data)
@@ -328,7 +328,7 @@ module.exports = defineConfig({
resolve: "./src/modules/agentic-commerce",
options: {
signatureKey: process.env.AGENTIC_COMMERCE_SIGNATURE_KEY || "supersecret",
}
},
},
],
})
@@ -487,7 +487,7 @@ export const getProductFeedItemsStep = createStep(
do {
const {
data: products,
metadata
metadata,
} = await query.graph({
entity: "product",
fields: [
@@ -503,7 +503,7 @@ export const getProductFeedItemsStep = createStep(
"sales_channels.*",
"sales_channels.stock_locations.*",
"sales_channels.stock_locations.address.*",
"categories.*"
"categories.*",
],
filters: {
status: "published",
@@ -513,19 +513,19 @@ export const getProductFeedItemsStep = createStep(
calculated_price: QueryContext({
currency_code: currencyCode,
}),
}
},
},
pagination: {
take: limit,
skip: offset,
}
},
})
count = metadata?.count ?? 0
offset += limit
for (const product of products) {
if (!product.variants.length) continue
if (!product.variants.length) {continue}
const salesChannel = product.sales_channels?.find((channel) => {
return channel?.stock_locations?.some((location) => {
return location?.address?.country_code.toLowerCase() === countryCode
@@ -752,11 +752,11 @@ export const sendProductFeedWorkflow = createWorkflow(
const { items: feedItems } = getProductFeedItemsStep(input)
const xml = buildProductFeedXmlStep({
items: feedItems
items: feedItems,
})
sendProductFeedStep({
productFeed: xml
productFeed: xml,
})
return new WorkflowResponse({ xml })
@@ -786,9 +786,9 @@ Create the file `src/jobs/sync-product-feed.ts` with the following content:
```ts title="src/jobs/sync-product-feed.ts"
import {
MedusaContainer
} from "@medusajs/framework/types";
import sendProductFeedWorkflow from "../workflows/send-product-feed";
MedusaContainer,
} from "@medusajs/framework/types"
import sendProductFeedWorkflow from "../workflows/send-product-feed"
export default async function syncProductFeed(container: MedusaContainer) {
const logger = container.resolve("logger")
@@ -816,7 +816,7 @@ export default async function syncProductFeed(container: MedusaContainer) {
export const config = {
name: "sync-product-feed",
schedule: "*/15 * * * *", // Every 15 minutes
};
}
```
In a scheduled job file, you must export:
@@ -890,11 +890,11 @@ To create the workflow, create the file `src/workflows/prepare-checkout-session-
import {
createWorkflow,
transform,
WorkflowResponse
WorkflowResponse,
} from "@medusajs/framework/workflows-sdk"
import {
listShippingOptionsForCartWithPricingWorkflow,
useQueryGraphStep
useQueryGraphStep,
} from "@medusajs/medusa/core-flows"
export type PrepareCheckoutSessionDataWorkflowInput = {
@@ -960,21 +960,21 @@ const { data: carts } = useQueryGraphStep({
"original_item_total",
"shipping_total",
"metadata",
"order.id"
"order.id",
],
filters: {
id: input.cart_id,
},
options: {
throwIfKeyNotFound: true
}
throwIfKeyNotFound: true,
},
})
// Retrieve shipping options
const shippingOptions = listShippingOptionsForCartWithPricingWorkflow.runAsStep({
input: {
cart_id: carts[0].id,
}
},
})
// TODO prepare response
@@ -1022,7 +1022,7 @@ const responseData = transform({
item: {
id: item?.variant_id,
quantity: item?.quantity,
}
},
})),
fulfillment_address: data.input.fulfillment_address,
fulfillment_options: data.shippingOptions?.map((option) => ({
@@ -1080,7 +1080,7 @@ const responseData = transform({
display_name: "Total",
// @ts-ignore
amount: data.carts[0].total,
}
},
],
messages: data.input.messages || [],
links: [
@@ -1095,8 +1095,8 @@ const responseData = transform({
{
type: "seller_shop_policy",
value: "https://www.medusa-commerce.com/seller-shop-policy", // TODO: replace with actual seller shop policy
}
]
},
],
}
})
@@ -1215,7 +1215,7 @@ import {
createWorkflow,
transform,
when,
WorkflowResponse
WorkflowResponse,
} from "@medusajs/framework/workflows-sdk"
import {
addShippingMethodToCartWorkflow,
@@ -1223,10 +1223,10 @@ import {
CreateCartWorkflowInput,
createCustomersWorkflow,
listShippingOptionsForCartWithPricingWorkflow,
useQueryGraphStep
useQueryGraphStep,
} from "@medusajs/medusa/core-flows"
import {
prepareCheckoutSessionDataWorkflow
prepareCheckoutSessionDataWorkflow,
} from "./prepare-checkout-session-data"
type WorkflowInput = {
@@ -1270,7 +1270,7 @@ Replace the `TODO` in the workflow with the following:
```ts title="src/workflows/create-checkout-session.ts"
// validate item IDs
const variantIds = transform({
input
input,
}, (data) => {
return data.input.items.map((item) => item.id)
})
@@ -1280,11 +1280,11 @@ useQueryGraphStep({
entity: "variant",
fields: ["id"],
filters: {
id: variantIds
id: variantIds,
},
options: {
throwIfKeyNotFound: true
}
throwIfKeyNotFound: true,
},
})
// TODO retrieve region and sales channel
@@ -1305,9 +1305,9 @@ const { data: regions } = useQueryGraphStep({
fields: ["id"],
filters: {
countries: {
iso_2: "us"
}
}
iso_2: "us",
},
},
}).config({ name: "find-region" })
// get sales channel
@@ -1338,7 +1338,7 @@ const { data: customers } = useQueryGraphStep({
fields: ["id"],
filters: {
email: input.buyer?.email,
}
},
}).config({ name: "find-customer" })
// create customer if it does not exist
@@ -1354,9 +1354,9 @@ const createdCustomers = when ({ customers }, ({ customers }) =>
first_name: input.buyer?.first_name,
phone: input.buyer?.phone_number,
has_account: false,
}
]
}
},
],
},
})
})
@@ -1397,7 +1397,7 @@ const cartInput = transform({
return {
items: data.input.items.map((item) => ({
variant_id: item.id,
quantity: item.quantity
quantity: item.quantity,
})),
region_id: data.regions[0]?.id,
email: data.input.buyer?.email,
@@ -1416,12 +1416,12 @@ const cartInput = transform({
sales_channel_id: data.salesChannels[0]?.id,
metadata: {
is_checkout_session: true,
}
},
} as CreateCartWorkflowInput
})
const createdCart = createCartWorkflow.runAsStep({
input: cartInput
input: cartInput,
})
// TODO retrieve shipping options
@@ -1445,7 +1445,7 @@ when(input, (input) => !!input.fulfillment_address)
const shippingOptions = listShippingOptionsForCartWithPricingWorkflow.runAsStep({
input: {
cart_id: createdCart.id,
}
},
})
const shippingMethodData = transform({
@@ -1460,11 +1460,11 @@ when(input, (input) => !!input.fulfillment_address)
cart_id: data.createdCart.id,
options: [{
id: cheapestShippingOption.id,
}]
}],
}
})
addShippingMethodToCartWorkflow.runAsStep({
input: shippingMethodData
input: shippingMethodData,
})
})
@@ -1488,7 +1488,7 @@ const responseData = prepareCheckoutSessionDataWorkflow.runAsStep({
buyer: input.buyer,
fulfillment_address: input.fulfillment_address,
cart_id: createdCart.id,
}
},
})
return new WorkflowResponse(responseData)
@@ -1555,7 +1555,7 @@ export const POST = async (
input: req.validatedBody,
context: {
idempotencyKey: req.headers["idempotency-key"] as string,
}
},
})
res.set(responseHeaders).json(result)
@@ -1569,8 +1569,8 @@ export const POST = async (
code: "invalid",
content_type: "plain",
content: medusaError.message,
}
]
},
],
})
}
}
@@ -1593,8 +1593,8 @@ Next, you'll create a [middleware](!docs!/learn/fundamentals/api-routes/middlewa
Create the file `src/api/middlewares/validate-agentic-request.ts` with the following content:
```ts title="src/api/middlewares/validate-agentic-request.ts"
import { MedusaNextFunction, MedusaRequest, MedusaResponse } from "@medusajs/framework";
import { AGENTIC_COMMERCE_MODULE } from "../../modules/agentic-commerce";
import { MedusaNextFunction, MedusaRequest, MedusaResponse } from "@medusajs/framework"
import { AGENTIC_COMMERCE_MODULE } from "../../modules/agentic-commerce"
export async function validateAgenticRequest(
req: MedusaRequest,
@@ -1609,12 +1609,12 @@ export async function validateAgenticRequest(
const isTokenValid = await apiKeyModuleService.authenticate(apiKey || "")
const isSignatureValid = !!req.body || await agenticCommerceModuleService.verifySignature({
signature,
payload: req.body
payload: req.body,
})
if (!isTokenValid || !isSignatureValid) {
return res.status(401).json({
message: "Unauthorized"
message: "Unauthorized",
})
}
@@ -1642,24 +1642,24 @@ You apply middlewares in the `src/api/middlewares.ts` file. Create this file wit
import {
defineMiddlewares,
validateAndTransformBody,
} from "@medusajs/framework/http";
import { validateAgenticRequest } from "./middlewares/validate-agentic-request";
import { PostCreateSessionSchema } from "./checkout_sessions/route";
} from "@medusajs/framework/http"
import { validateAgenticRequest } from "./middlewares/validate-agentic-request"
import { PostCreateSessionSchema } from "./checkout_sessions/route"
export default defineMiddlewares({
routes: [
{
matcher: "/checkout_sessions*",
middlewares: [
validateAgenticRequest
]
validateAgenticRequest,
],
},
{
matcher: "/checkout_sessions",
method: ["POST"],
middlewares: [validateAndTransformBody(PostCreateSessionSchema)]
middlewares: [validateAndTransformBody(PostCreateSessionSchema)],
},
]
],
})
```
@@ -1678,7 +1678,7 @@ In `src/api/middlewares.ts`, add the following import at the top of the file:
```ts title="src/api/middlewares.ts"
import {
errorHandler,
} from "@medusajs/framework/http";
} from "@medusajs/framework/http"
const originalErrorHandler = errorHandler()
```
@@ -1702,8 +1702,8 @@ export default defineMiddlewares({
code: "invalid",
content_type: "plain",
content: error.message,
}
]
},
],
})
},
})
@@ -1935,16 +1935,16 @@ import {
createWorkflow,
transform,
when,
WorkflowResponse
WorkflowResponse,
} from "@medusajs/framework/workflows-sdk"
import {
addShippingMethodToCartWorkflow,
createCustomersWorkflow,
updateCartWorkflow,
useQueryGraphStep
useQueryGraphStep,
} from "@medusajs/medusa/core-flows"
import {
prepareCheckoutSessionDataWorkflow
prepareCheckoutSessionDataWorkflow,
} from "./prepare-checkout-session-data"
type WorkflowInput = {
@@ -1980,7 +1980,7 @@ export const updateCheckoutSessionWorkflow = createWorkflow(
fields: ["id", "customer.*", "email"],
filters: {
id: input.cart_id,
}
},
})
// TODO retrieve or create customer
@@ -2003,7 +2003,7 @@ const { data: customers } = useQueryGraphStep({
fields: ["id"],
filters: {
email: input.buyer?.email,
}
},
}).config({ name: "find-customer" })
const createdCustomers = when({ customers }, ({ customers }) =>
@@ -2017,9 +2017,9 @@ const createdCustomers = when({ customers }, ({ customers }) =>
email: input.buyer?.email,
first_name: input.buyer?.first_name,
phone: input.buyer?.phone_number,
}
},
],
}
},
})
})
@@ -2057,7 +2057,7 @@ when(input, (input) => !!input.items)
},
options: {
throwIfKeyNotFound: true,
}
},
}).config({ name: "find-variant" })
})
@@ -2133,7 +2133,7 @@ const responseData = prepareCheckoutSessionDataWorkflow.runAsStep({
cart_id: updateData.id,
buyer: input.buyer,
fulfillment_address: input.fulfillment_address,
}
},
})
return new WorkflowResponse(responseData)
@@ -2199,7 +2199,7 @@ export const POST = async (
},
context: {
idempotencyKey: req.headers["idempotency-key"] as string,
}
},
})
res.set(responseHeaders).json(result)
@@ -2209,7 +2209,7 @@ export const POST = async (
await refreshPaymentCollectionForCartWorkflow(req.scope).run({
input: {
cart_id: req.params.id,
}
},
})
const { result } = await prepareCheckoutSessionDataWorkflow(req.scope)
@@ -2224,8 +2224,8 @@ export const POST = async (
"payment_declined" : "invalid",
content_type: "plain",
content: medusaError.message,
}
]
},
],
},
})
@@ -2249,7 +2249,7 @@ Finally, you'll apply the validation middleware to the `POST /checkout_sessions/
In `src/api/middlewares.ts`, add the following import at the top of the file:
```ts title="src/api/middlewares.ts"
import { PostUpdateSessionSchema } from "./checkout_sessions/[id]/route";
import { PostUpdateSessionSchema } from "./checkout_sessions/[id]/route"
```
Then, add a new route configuration in `defineMiddlewares`:
@@ -2261,7 +2261,7 @@ export default defineMiddlewares({
{
matcher: "/checkout_sessions/:id",
method: ["POST"],
middlewares: [validateAndTransformBody(PostUpdateSessionSchema)]
middlewares: [validateAndTransformBody(PostUpdateSessionSchema)],
},
],
// ...
@@ -2346,7 +2346,7 @@ export const GET = async (
},
context: {
idempotencyKey: req.headers["idempotency-key"] as string,
}
},
})
res.set(responseHeaders).status(201).json(result)
@@ -2499,7 +2499,7 @@ import {
createWorkflow,
transform,
when,
WorkflowResponse
WorkflowResponse,
} from "@medusajs/framework/workflows-sdk"
import {
completeCartWorkflow,
@@ -2507,11 +2507,11 @@ import {
createPaymentSessionsWorkflow,
refreshPaymentCollectionForCartWorkflow,
updateCartWorkflow,
useQueryGraphStep
useQueryGraphStep,
} from "@medusajs/medusa/core-flows"
import {
prepareCheckoutSessionDataWorkflow,
PrepareCheckoutSessionDataWorkflowInput
PrepareCheckoutSessionDataWorkflowInput,
} from "./prepare-checkout-session-data"
type WorkflowInput = {
@@ -2547,7 +2547,7 @@ export const completeCheckoutSessionWorkflow = createWorkflow(
"id",
"region.*",
"region.payment_providers.*",
"shipping_address.*"
"shipping_address.*",
],
filters: {
id: input.cart_id,
@@ -2589,7 +2589,7 @@ when(input, (input) => !!input.payment_data.billing_address)
postal_code: data.input.payment_data.billing_address!.postal_code,
country_code: data.input.payment_data.billing_address!.country,
phone: data.input.payment_data.billing_address!.phone_number,
}
},
}
})
return updateCartWorkflow.runAsStep({
@@ -2628,7 +2628,7 @@ const preparationInput = transform({
})
const paymentProviderId = transform({
input
input,
}, (data) => {
switch (data.input.payment_data.provider) {
case "stripe":
@@ -2640,7 +2640,7 @@ const paymentProviderId = transform({
const completeCartResponse = when({
carts,
paymentProviderId
paymentProviderId,
}, (data) => {
// @ts-ignore
return !!data.carts[0].region?.payment_providers?.find((provider) => provider?.id === data.paymentProviderId)
@@ -2649,7 +2649,7 @@ const completeCartResponse = when({
const paymentCollection = createPaymentCollectionForCartWorkflow.runAsStep({
input: {
cart_id: carts[0].id,
}
},
})
createPaymentSessionsWorkflow.runAsStep({
@@ -2658,14 +2658,14 @@ const completeCartResponse = when({
provider_id: paymentProviderId,
data: {
shared_payment_token: input.payment_data.token,
}
}
},
},
})
completeCartWorkflow.runAsStep({
input: {
id: carts[0].id,
}
},
})
return prepareCheckoutSessionDataWorkflow.runAsStep({
@@ -2695,7 +2695,7 @@ Replace the `TODO` in the workflow with the following:
```ts title="src/workflows/complete-checkout-session.ts"
const invalidPaymentResponse = when({
carts,
paymentProviderId
paymentProviderId,
}, (data) => {
return !data.carts[0].region?.payment_providers?.find((provider) => provider?.id === data.paymentProviderId)
})
@@ -2703,7 +2703,7 @@ const invalidPaymentResponse = when({
refreshPaymentCollectionForCartWorkflow.runAsStep({
input: {
cart_id: carts[0].id,
}
},
})
const prepareDataWithMessages = transform({
prepareData: preparationInput,
@@ -2716,12 +2716,12 @@ const invalidPaymentResponse = when({
code: "invalid",
content_type: "plain",
content: "Invalid payment provider",
}
]
},
],
} as PrepareCheckoutSessionDataWorkflowInput
})
return prepareCheckoutSessionDataWorkflow.runAsStep({
input: prepareDataWithMessages
input: prepareDataWithMessages,
}).config({ name: "prepare-checkout-session-data-with-messages" })
})
@@ -2739,7 +2739,7 @@ Finally, you'll return the appropriate response based on whether the cart was co
```ts title="src/workflows/complete-checkout-session.ts"
const responseData = transform({
completeCartResponse,
invalidPaymentResponse
invalidPaymentResponse,
}, (data) => {
return data.completeCartResponse || data.invalidPaymentResponse
})
@@ -2804,7 +2804,7 @@ export const POST = async (
},
context: {
idempotencyKey: req.headers["idempotency-key"] as string,
}
},
})
res.set(responseHeaders).json(result)
@@ -2814,7 +2814,7 @@ export const POST = async (
await refreshPaymentCollectionForCartWorkflow(req.scope).run({
input: {
cart_id: req.params.id,
}
},
})
const { result } = await prepareCheckoutSessionDataWorkflow(req.scope)
.run({
@@ -2828,8 +2828,8 @@ export const POST = async (
"payment_declined" : "invalid",
content_type: "plain",
content: medusaError.message,
}
]
},
],
},
})
@@ -2853,7 +2853,7 @@ Finally, you'll apply the validation middleware to the `POST /checkout_sessions/
In `src/api/middlewares.ts`, add the following import at the top of the file:
```ts title="src/api/middlewares.ts"
import { PostCompleteSessionSchema } from "./checkout_sessions/[id]/complete/route";
import { PostCompleteSessionSchema } from "./checkout_sessions/[id]/complete/route"
```
Then, add a new route configuration in `defineMiddlewares`:
@@ -2865,7 +2865,7 @@ export default defineMiddlewares({
{
matcher: "/checkout_sessions/:id/complete",
method: ["POST"],
middlewares: [validateAndTransformBody(PostCompleteSessionSchema)]
middlewares: [validateAndTransformBody(PostCompleteSessionSchema)],
},
],
// ...
@@ -3190,14 +3190,14 @@ export const cancelCheckoutSessionWorkflow = createWorkflow(
"id",
"payment_collection.*",
"payment_collection.payment_sessions.*",
"order.id"
"order.id",
],
filters: {
id: input.cart_id,
},
options: {
throwIfKeyNotFound: true,
}
},
})
validateCartCancelationStep({
@@ -3217,11 +3217,11 @@ Next, you'll cancel the payment sessions if there are any. Replace the `TODO` in
```ts title="src/workflows/cancel-checkout-session.ts"
when({
carts
carts,
}, (data) => !!data.carts[0].payment_collection?.payment_sessions?.length)
.then(() => {
const paymentSessionIds = transform({
carts
carts,
}, (data) => {
return data.carts[0].payment_collection?.payment_sessions?.map((session) => session!.id)
})
@@ -3235,8 +3235,8 @@ updateCartWorkflow.runAsStep({
id: carts[0].id,
metadata: {
checkout_session_canceled: true,
}
}
},
},
})
// TODO prepare and return response
@@ -3252,7 +3252,7 @@ Finally, you'll prepare and return the checkout session response. Replace the `T
const responseData = prepareCheckoutSessionDataWorkflow.runAsStep({
input: {
cart_id: carts[0].id,
}
},
})
return new WorkflowResponse(responseData)
@@ -3287,7 +3287,7 @@ export const POST = async (
},
context: {
idempotencyKey: req.headers["idempotency-key"] as string,
}
},
})
res.set(responseHeaders).json(result)
@@ -3300,8 +3300,8 @@ export const POST = async (
code: "invalid",
content_type: "plain",
content: medusaError.message,
}
]
},
],
})
}
}
@@ -3382,7 +3382,7 @@ export default async function orderWebhookHandler({
],
filters: {
id: orderId,
}
},
})
// only send webhook if order is associated with a checkout session
@@ -3404,7 +3404,7 @@ export default async function orderWebhookHandler({
type: "original_payment",
amount: transaction!.amount * -1,
})) || [],
}
},
}
// set status based on order, fulfillments and transactions