feat(orders): pass the CMS's status and safe error fields to the browser

The order routes (get, put, add-product, remove-product, checkout, capture)
call forwardToCms, which throws a CMS error on as
createError({ statusCode, statusMessage, data: { message, errors?, missing? } }),
built by the pure shopErrorFromCms (server/utils/cmsError.ts).

Before, the FetchError was thrown on as it was: the browser got the CMS's
status, but Nitro treated it as unhandled, answered "Server Error" without
data and logged every CMS 4xx as [unhandled]. Now the browser also gets the
CMS's message, the errors of a rejected update and the fields a checkout
misses, and no other field. A status that is the shop's own fault (401, 403,
...) is answered 500, a CMS that does not answer 503; 5xx are logged without
the query and the order uuid.

npm test runs tests/unit with Node's type stripping and no dependencies, as
in libreshop/cms. nuxt.config keeps tests/ out of the app's type check.

Refs libretech/mp#71
This commit is contained in:
2026-10-09 02:32:14 +02:00
parent 61a74e649b
commit 5c773a99e6
13 changed files with 338 additions and 14 deletions
+2 -2
View File
@@ -1,4 +1,4 @@
import { fetchCms } from "~/server/utils/cmsApi";
import { forwardToCms } from "~/server/utils/cmsApi";
export default defineEventHandler(async (event) => {
const uuid = getRouterParam(event, "uuid");
@@ -6,5 +6,5 @@ export default defineEventHandler(async (event) => {
throw createError({ statusCode: 400, statusMessage: "Missing order UUID" });
}
return await fetchCms(`/orders/${uuid}/cart`);
return await forwardToCms(`/orders/${uuid}/cart`);
});
+2 -2
View File
@@ -1,4 +1,4 @@
import { fetchCms } from "~/server/utils/cmsApi";
import { forwardToCms } from "~/server/utils/cmsApi";
export default defineEventHandler(async (event) => {
const uuid = getRouterParam(event, "uuid");
@@ -8,7 +8,7 @@ export default defineEventHandler(async (event) => {
const body = await readBody(event);
return await fetchCms(`/orders/${uuid}/cart`, {
return await forwardToCms(`/orders/${uuid}/cart`, {
method: "PUT",
body
});
@@ -1,4 +1,4 @@
import { fetchCms } from "~/server/utils/cmsApi";
import { forwardToCms } from "~/server/utils/cmsApi";
export default defineEventHandler(async (event) => {
const uuid = getRouterParam(event, "uuid");
@@ -14,7 +14,7 @@ export default defineEventHandler(async (event) => {
const count = query.count || 1;
return await fetchCms(`/orders/${uuid}/add-product/${productId}?count=${count}`, {
return await forwardToCms(`/orders/${uuid}/add-product/${productId}?count=${count}`, {
method: "PUT"
});
});
@@ -1,4 +1,4 @@
import { fetchCms } from "~/server/utils/cmsApi";
import { forwardToCms } from "~/server/utils/cmsApi";
export default defineEventHandler(async (event) => {
const uuid = getRouterParam(event, "uuid");
@@ -11,7 +11,7 @@ export default defineEventHandler(async (event) => {
throw createError({ statusCode: 400, statusMessage: "Missing PayPal order ID" });
}
return await fetchCms(`/orders/${uuid}/capture/${paypalOrderId}`, {
return await forwardToCms(`/orders/${uuid}/capture/${paypalOrderId}`, {
method: "POST"
});
});
+2 -2
View File
@@ -1,4 +1,4 @@
import { fetchCms } from "~/server/utils/cmsApi";
import { forwardToCms } from "~/server/utils/cmsApi";
export default defineEventHandler(async (event) => {
const uuid = getRouterParam(event, "uuid");
@@ -10,7 +10,7 @@ export default defineEventHandler(async (event) => {
const returnUrl = query.returnUrl || "";
return await fetchCms(`/orders/${uuid}/checkout?returnUrl=${encodeURIComponent(String(returnUrl))}`, {
return await forwardToCms(`/orders/${uuid}/checkout?returnUrl=${encodeURIComponent(String(returnUrl))}`, {
method: "POST"
});
});
@@ -1,4 +1,4 @@
import { fetchCms } from "~/server/utils/cmsApi";
import { forwardToCms } from "~/server/utils/cmsApi";
export default defineEventHandler(async (event) => {
const uuid = getRouterParam(event, "uuid");
@@ -14,7 +14,7 @@ export default defineEventHandler(async (event) => {
const count = query.count || 1;
return await fetchCms(`/orders/${uuid}/remove-product/${productId}?count=${count}`, {
return await forwardToCms(`/orders/${uuid}/remove-product/${productId}?count=${count}`, {
method: "PUT"
});
});