feat(mcp): implement upstream origin resolution for internal API calls
- Added a new `upstreamOrigin` function to resolve the correct upstream API origin for internal MCP to REST calls, addressing issues with container deployments where `req.nextUrl.origin` resolves incorrectly. - The function prioritizes environment variables for configuration, ensuring proper routing in various deployment scenarios. - Updated multiple API fetch calls to utilize the new `upstreamOrigin` function, improving reliability and consistency in internal API interactions.
This commit is contained in:
parent
e7672ab7c9
commit
e5e31a7bdc
1 changed files with 87 additions and 45 deletions
|
|
@ -95,6 +95,42 @@ function withCors(response: NextResponse, req: NextRequest): NextResponse {
|
|||
* JSON-RPC `result` is still populated so older clients that only
|
||||
* look at the envelope keep working.
|
||||
*/
|
||||
/**
|
||||
* Resolve the upstream `/api/v1` origin for internal MCP → REST
|
||||
* loopback calls.
|
||||
*
|
||||
* Why this exists: in container deployments (Coolify, Docker, k8s)
|
||||
* `req.nextUrl.origin` resolves to the bind socket — typically
|
||||
* `https://0.0.0.0:3000` because the Dockerfile sets
|
||||
* `HOSTNAME="0.0.0.0"`. That URL doesn't route outbound and the
|
||||
* plain-HTTP container answers with an SSL handshake mismatch
|
||||
* (`ERR_SSL_WRONG_VERSION_NUMBER`), surfacing as `-32010 / fetch
|
||||
* failed` on every internal fetch.
|
||||
*
|
||||
* Resolution order:
|
||||
* 1. `AGENT_API_BASE_URL` env var — explicit override; set this in
|
||||
* the deploy env to the public origin (e.g.
|
||||
* `https://wfdash.apphub.co.za`) or, for in-container loopback,
|
||||
* `http://127.0.0.1:3000`.
|
||||
* 2. `NEXT_PUBLIC_BASE_URL` env var — secondary override; mostly
|
||||
* for symmetry with other parts of the app.
|
||||
* 3. `req.url` parsed — works correctly for non-container deploys
|
||||
* and dev (`localhost:4001`).
|
||||
*
|
||||
* Note: the URL is constructed via `new URL()` not string concat, so
|
||||
* an env var without a scheme is rejected cleanly (Node throws) rather
|
||||
* than silently becoming a malformed upstream.
|
||||
*/
|
||||
function upstreamOrigin(req: NextRequest): string {
|
||||
const fromEnv =
|
||||
process.env.AGENT_API_BASE_URL || process.env.NEXT_PUBLIC_BASE_URL;
|
||||
if (fromEnv) {
|
||||
// Validate; throws on malformed.
|
||||
return new URL(fromEnv).origin;
|
||||
}
|
||||
return new URL(req.url).origin;
|
||||
}
|
||||
|
||||
function jsonRpcOk(id: unknown, result: unknown, status?: number) {
|
||||
const body = {
|
||||
jsonrpc: "2.0",
|
||||
|
|
@ -3358,7 +3394,7 @@ export async function POST(req: NextRequest) {
|
|||
if (typeof args.kind === "string") fd.append("kind", args.kind);
|
||||
|
||||
const res = await fetch(
|
||||
`${req.nextUrl.origin}/api/v1/orders/${args.order_id}/attachments/upload`,
|
||||
`${upstreamOrigin(req)}/api/v1/orders/${args.order_id}/attachments/upload`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
|
|
@ -3379,7 +3415,7 @@ export async function POST(req: NextRequest) {
|
|||
throw new Error("Missing order_id for orders.list_attachments.");
|
||||
}
|
||||
const data = await fetchUpstreamJson(
|
||||
`${req.nextUrl.origin}/api/v1/orders/${args.order_id}/matched-attachments`,
|
||||
`${upstreamOrigin(req)}/api/v1/orders/${args.order_id}/matched-attachments`,
|
||||
{ method: "GET" },
|
||||
"orders.list_attachments",
|
||||
);
|
||||
|
|
@ -3414,7 +3450,7 @@ export async function POST(req: NextRequest) {
|
|||
// step (idempotency on message_id, sentinel-customer fallback,
|
||||
// ai_status="pending" stamp).
|
||||
const data = await fetchUpstreamJson(
|
||||
`${req.nextUrl.origin}/api/v1/quotes/from-email`,
|
||||
`${upstreamOrigin(req)}/api/v1/quotes/from-email`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: { "content-type": "application/json" },
|
||||
|
|
@ -3443,7 +3479,7 @@ export async function POST(req: NextRequest) {
|
|||
// Auth-required by the upstream route. Forward the agent key.
|
||||
const limit = typeof args.limit === "number" ? args.limit : 5;
|
||||
const res = await fetch(
|
||||
`${req.nextUrl.origin}/api/v1/quotes/process-pending?limit=${encodeURIComponent(String(limit))}`,
|
||||
`${upstreamOrigin(req)}/api/v1/quotes/process-pending?limit=${encodeURIComponent(String(limit))}`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
|
|
@ -3475,7 +3511,7 @@ export async function POST(req: NextRequest) {
|
|||
}
|
||||
const hintEntry = TOOL_HINTS["quotes.create"];
|
||||
const data = await fetchUpstreamJson(
|
||||
`${req.nextUrl.origin}/api/v1/quotes/create`,
|
||||
`${upstreamOrigin(req)}/api/v1/quotes/create`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
|
|
@ -3504,7 +3540,7 @@ export async function POST(req: NextRequest) {
|
|||
if (!args.id) throw new Error("Missing id for quotes.re_run_ai.");
|
||||
const wipe = args.wipe_items === false ? "false" : "true";
|
||||
const res = await fetch(
|
||||
`${req.nextUrl.origin}/api/v1/quotes/${encodeURIComponent(String(args.id))}/re-run-ai?wipe_items=${wipe}`,
|
||||
`${upstreamOrigin(req)}/api/v1/quotes/${encodeURIComponent(String(args.id))}/re-run-ai?wipe_items=${wipe}`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
|
|
@ -3575,12 +3611,18 @@ export async function POST(req: NextRequest) {
|
|||
}
|
||||
|
||||
if (toolName === "quotes.list_attachments") {
|
||||
if (!args.quote_id) throw new Error("Missing quote_id for quotes.list_attachments.");
|
||||
const quoteId = String(args.quote_id);
|
||||
// Schema/route alignment: tool catalog advertises the param as
|
||||
// `id` (matching the REST `[id]` path), but this handler used to
|
||||
// require `quote_id`. Accept either so callers using either
|
||||
// name don't 500 before the fetch even runs. Hermes (and the
|
||||
// auto-gen docs) use `id`.
|
||||
const quoteId = args.id ?? args.quote_id;
|
||||
if (!quoteId) throw new Error("Missing id (or quote_id) for quotes.list_attachments.");
|
||||
const quoteIdStr = String(quoteId);
|
||||
const page = Number(args.page || 1);
|
||||
const perPage = Math.min(500, Number(args.perPage || 50));
|
||||
const data = await fetchUpstreamJson(
|
||||
`${req.nextUrl.origin}/api/v1/quotes/${quoteId}/attachments?page=${page}&perPage=${perPage}`,
|
||||
`${upstreamOrigin(req)}/api/v1/quotes/${quoteIdStr}/attachments?page=${page}&perPage=${perPage}`,
|
||||
{ method: "GET" },
|
||||
"quotes.list_attachments",
|
||||
);
|
||||
|
|
@ -3596,7 +3638,7 @@ export async function POST(req: NextRequest) {
|
|||
const qs = params.toString();
|
||||
const hintEntry = TOOL_HINTS["quotes.get_pdf"];
|
||||
const data = await fetchUpstreamJson(
|
||||
`${req.nextUrl.origin}/api/v1/quotes/${quoteId}/pdf/base64${qs ? `?${qs}` : ""}`,
|
||||
`${upstreamOrigin(req)}/api/v1/quotes/${quoteId}/pdf/base64${qs ? `?${qs}` : ""}`,
|
||||
{ method: "GET" },
|
||||
"quotes.get_pdf",
|
||||
{ hint: hintEntry?.hint, nextActions: hintEntry?.nextActions },
|
||||
|
|
@ -4036,7 +4078,7 @@ export async function POST(req: NextRequest) {
|
|||
if (args.regenerate_pdf === true) {
|
||||
const letterhead = (updated.company_letterhead as string) || "CNL";
|
||||
const pdfRes = await fetch(
|
||||
`${req.nextUrl.origin}/api/v1/quotes/${args.id}/pdf`,
|
||||
`${upstreamOrigin(req)}/api/v1/quotes/${args.id}/pdf`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
|
|
@ -4090,7 +4132,7 @@ export async function POST(req: NextRequest) {
|
|||
|
||||
if (toolName === "quotes.clone") {
|
||||
if (!args.id) throw new Error("Missing id for quotes.clone.");
|
||||
const res = await fetch(`${req.nextUrl.origin}/api/v1/quotes/${args.id}/clone`, {
|
||||
const res = await fetch(`${upstreamOrigin(req)}/api/v1/quotes/${args.id}/clone`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
|
|
@ -4109,7 +4151,7 @@ export async function POST(req: NextRequest) {
|
|||
throw new Error("Missing template_id for quotes.create_from_template.");
|
||||
}
|
||||
const res = await fetch(
|
||||
`${req.nextUrl.origin}/api/v1/quotes/${args.template_id}/create-from-template`,
|
||||
`${upstreamOrigin(req)}/api/v1/quotes/${args.template_id}/create-from-template`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
|
|
@ -4128,7 +4170,7 @@ export async function POST(req: NextRequest) {
|
|||
if (toolName === "quotes.save_as_template") {
|
||||
if (!args.id) throw new Error("Missing id for quotes.save_as_template.");
|
||||
const res = await fetch(
|
||||
`${req.nextUrl.origin}/api/v1/quotes/${args.id}/save-as-template`,
|
||||
`${upstreamOrigin(req)}/api/v1/quotes/${args.id}/save-as-template`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
|
|
@ -4149,7 +4191,7 @@ export async function POST(req: NextRequest) {
|
|||
if (!args.source_quote_id) {
|
||||
throw new Error("Missing source_quote_id for quotes.split.");
|
||||
}
|
||||
const res = await fetch(`${req.nextUrl.origin}/api/v1/quotes/${args.source_quote_id}/split`, {
|
||||
const res = await fetch(`${upstreamOrigin(req)}/api/v1/quotes/${args.source_quote_id}/split`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
|
|
@ -4170,7 +4212,7 @@ export async function POST(req: NextRequest) {
|
|||
}
|
||||
const hintEntry = TOOL_HINTS["quotes.partial_approve"];
|
||||
const data = await fetchUpstreamJson(
|
||||
`${req.nextUrl.origin}/api/v1/quotes/${args.quote_id}/partial-approve`,
|
||||
`${upstreamOrigin(req)}/api/v1/quotes/${args.quote_id}/partial-approve`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
|
|
@ -4190,7 +4232,7 @@ export async function POST(req: NextRequest) {
|
|||
}
|
||||
const hintEntry = TOOL_HINTS["quotes.submit"];
|
||||
const data = await fetchUpstreamJson(
|
||||
`${req.nextUrl.origin}/api/v1/quotes/${args.id}/submit`,
|
||||
`${upstreamOrigin(req)}/api/v1/quotes/${args.id}/submit`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
|
|
@ -4209,7 +4251,7 @@ export async function POST(req: NextRequest) {
|
|||
if (!Array.isArray(args.items)) {
|
||||
throw new Error("Missing items array for quotes.re_price.");
|
||||
}
|
||||
const res = await fetch(`${req.nextUrl.origin}/api/v1/quotes/${args.id}/re-price`, {
|
||||
const res = await fetch(`${upstreamOrigin(req)}/api/v1/quotes/${args.id}/re-price`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
|
|
@ -4238,7 +4280,7 @@ export async function POST(req: NextRequest) {
|
|||
if (args.q) params.set("q", String(args.q));
|
||||
if (args.page) params.set("page", String(args.page));
|
||||
if (args.limit) params.set("limit", String(args.limit));
|
||||
const res = await fetch(`${req.nextUrl.origin}/api/v1/quotes/lookup?${params}`, {
|
||||
const res = await fetch(`${upstreamOrigin(req)}/api/v1/quotes/lookup?${params}`, {
|
||||
headers: { authorization: `Bearer ${process.env.AGENT_API_KEY ?? ""}` },
|
||||
});
|
||||
if (!res.ok) throw new Error(`quotes.lookup upstream ${res.status}`);
|
||||
|
|
@ -4353,7 +4395,7 @@ export async function POST(req: NextRequest) {
|
|||
if (args.olderThan) params.set("olderThan", String(args.olderThan));
|
||||
if (args.limit) params.set("limit", String(args.limit));
|
||||
const res = await fetch(
|
||||
`${req.nextUrl.origin}/api/v1/purchase-orders/stale?${params}`,
|
||||
`${upstreamOrigin(req)}/api/v1/purchase-orders/stale?${params}`,
|
||||
{ headers: { authorization: `Bearer ${process.env.AGENT_API_KEY ?? ""}` } },
|
||||
);
|
||||
if (!res.ok) throw new Error(`purchase_orders.stale upstream ${res.status}`);
|
||||
|
|
@ -5318,7 +5360,7 @@ export async function POST(req: NextRequest) {
|
|||
body.intent = args.intent;
|
||||
}
|
||||
if (typeof args.notes === "string") body.notes = args.notes;
|
||||
const res = await fetch(`${req.nextUrl.origin}/api/v1/stock/fulfill`, {
|
||||
const res = await fetch(`${upstreamOrigin(req)}/api/v1/stock/fulfill`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
|
|
@ -5337,7 +5379,7 @@ export async function POST(req: NextRequest) {
|
|||
if (!args.order_item_id || typeof args.surplus_qty !== "number") {
|
||||
throw new Error("order_item_id and surplus_qty are required.");
|
||||
}
|
||||
const res = await fetch(`${req.nextUrl.origin}/api/v1/stock/surplus-book`, {
|
||||
const res = await fetch(`${upstreamOrigin(req)}/api/v1/stock/surplus-book`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
|
|
@ -5387,7 +5429,7 @@ export async function POST(req: NextRequest) {
|
|||
// api_key never crosses the boundary here; the upstream route
|
||||
// strips it before responding.
|
||||
if (toolName === "ai_settings.get") {
|
||||
const res = await fetch(`${req.nextUrl.origin}/api/v1/ai/settings`, {
|
||||
const res = await fetch(`${upstreamOrigin(req)}/api/v1/ai/settings`, {
|
||||
headers: {
|
||||
authorization: `Bearer ${process.env.AGENT_API_KEY ?? ""}`,
|
||||
},
|
||||
|
|
@ -5406,7 +5448,7 @@ export async function POST(req: NextRequest) {
|
|||
if (typeof args.model_id === "string") patch.model_id = args.model_id;
|
||||
if (typeof args.max_tokens === "number") patch.max_tokens = args.max_tokens;
|
||||
if (typeof args.enabled === "boolean") patch.enabled = args.enabled;
|
||||
const res = await fetch(`${req.nextUrl.origin}/api/v1/ai/settings`, {
|
||||
const res = await fetch(`${upstreamOrigin(req)}/api/v1/ai/settings`, {
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"content-type": "application/json",
|
||||
|
|
@ -5580,7 +5622,7 @@ export async function POST(req: NextRequest) {
|
|||
|
||||
// ─── Users (lookup) ──────────────────────────────────────────────
|
||||
if (toolName === "users.lookup") {
|
||||
const res = await fetch(`${req.nextUrl.origin}/api/v1/users/lookup`, {
|
||||
const res = await fetch(`${upstreamOrigin(req)}/api/v1/users/lookup`, {
|
||||
method: "GET",
|
||||
headers: { authorization: `Bearer ${process.env.AGENT_API_KEY ?? ""}` },
|
||||
});
|
||||
|
|
@ -5593,7 +5635,7 @@ export async function POST(req: NextRequest) {
|
|||
|
||||
// ─── Dashboard / aggregate ───────────────────────────────────────
|
||||
if (toolName === "dashboard.daily_summary") {
|
||||
const res = await fetch(`${req.nextUrl.origin}/api/v1/dashboard`, {
|
||||
const res = await fetch(`${upstreamOrigin(req)}/api/v1/dashboard`, {
|
||||
method: "GET",
|
||||
headers: { authorization: `Bearer ${process.env.AGENT_API_KEY ?? ""}` },
|
||||
});
|
||||
|
|
@ -5605,7 +5647,7 @@ export async function POST(req: NextRequest) {
|
|||
}
|
||||
|
||||
if (toolName === "orders.sprint_counts") {
|
||||
const res = await fetch(`${req.nextUrl.origin}/api/v1/orders/sprint/counts`, {
|
||||
const res = await fetch(`${upstreamOrigin(req)}/api/v1/orders/sprint/counts`, {
|
||||
method: "GET",
|
||||
headers: { authorization: `Bearer ${process.env.AGENT_API_KEY ?? ""}` },
|
||||
});
|
||||
|
|
@ -5617,7 +5659,7 @@ export async function POST(req: NextRequest) {
|
|||
}
|
||||
|
||||
if (toolName === "orders.find_duplicates") {
|
||||
const res = await fetch(`${req.nextUrl.origin}/api/v1/orders/duplicates`, {
|
||||
const res = await fetch(`${upstreamOrigin(req)}/api/v1/orders/duplicates`, {
|
||||
method: "GET",
|
||||
headers: { authorization: `Bearer ${process.env.AGENT_API_KEY ?? ""}` },
|
||||
});
|
||||
|
|
@ -5631,7 +5673,7 @@ export async function POST(req: NextRequest) {
|
|||
// ─── Orders side helpers ─────────────────────────────────────────
|
||||
if (toolName === "orders.review") {
|
||||
if (!args.id) throw new Error("Missing id for orders.review.");
|
||||
const res = await fetch(`${req.nextUrl.origin}/api/v1/orders/${args.id}/review`, {
|
||||
const res = await fetch(`${upstreamOrigin(req)}/api/v1/orders/${args.id}/review`, {
|
||||
method: "GET",
|
||||
headers: { authorization: `Bearer ${process.env.AGENT_API_KEY ?? ""}` },
|
||||
});
|
||||
|
|
@ -5645,7 +5687,7 @@ export async function POST(req: NextRequest) {
|
|||
if (toolName === "orders.matched_attachments") {
|
||||
if (!args.id) throw new Error("Missing id for orders.matched_attachments.");
|
||||
const res = await fetch(
|
||||
`${req.nextUrl.origin}/api/v1/orders/${args.id}/matched-attachments`,
|
||||
`${upstreamOrigin(req)}/api/v1/orders/${args.id}/matched-attachments`,
|
||||
{
|
||||
method: "GET",
|
||||
headers: { authorization: `Bearer ${process.env.AGENT_API_KEY ?? ""}` },
|
||||
|
|
@ -5668,7 +5710,7 @@ export async function POST(req: NextRequest) {
|
|||
"Missing collection / record_id / filename for files.fetch.",
|
||||
);
|
||||
}
|
||||
const url = `${req.nextUrl.origin}/api/v1/files/${encodeURIComponent(
|
||||
const url = `${upstreamOrigin(req)}/api/v1/files/${encodeURIComponent(
|
||||
args.collection,
|
||||
)}/${encodeURIComponent(args.record_id)}/${encodeURIComponent(args.filename)}`;
|
||||
const res = await fetch(url, {
|
||||
|
|
@ -5697,7 +5739,7 @@ export async function POST(req: NextRequest) {
|
|||
qs.set("page", String(args.page ?? 1));
|
||||
qs.set("perPage", String(args.perPage ?? 50));
|
||||
const res = await fetch(
|
||||
`${req.nextUrl.origin}/api/v1/driver/stops?${qs}`,
|
||||
`${upstreamOrigin(req)}/api/v1/driver/stops?${qs}`,
|
||||
{
|
||||
method: "GET",
|
||||
headers: { authorization: `Bearer ${process.env.AGENT_API_KEY ?? ""}` },
|
||||
|
|
@ -5715,7 +5757,7 @@ export async function POST(req: NextRequest) {
|
|||
throw new Error("Missing stop_id / kind / action for drivers.update_stop_status.");
|
||||
}
|
||||
const res = await fetch(
|
||||
`${req.nextUrl.origin}/api/v1/driver/stops/${encodeURIComponent(args.stop_id)}/status`,
|
||||
`${upstreamOrigin(req)}/api/v1/driver/stops/${encodeURIComponent(args.stop_id)}/status`,
|
||||
{
|
||||
method: "PATCH",
|
||||
headers: {
|
||||
|
|
@ -5747,7 +5789,7 @@ export async function POST(req: NextRequest) {
|
|||
const qs = new URLSearchParams({ q: args.q });
|
||||
if (args.limit) qs.set("limit", String(args.limit));
|
||||
const res = await fetch(
|
||||
`${req.nextUrl.origin}/api/v1/stock-quick-draft/search?${qs}`,
|
||||
`${upstreamOrigin(req)}/api/v1/stock-quick-draft/search?${qs}`,
|
||||
{
|
||||
method: "GET",
|
||||
headers: { authorization: `Bearer ${process.env.AGENT_API_KEY ?? ""}` },
|
||||
|
|
@ -5772,7 +5814,7 @@ export async function POST(req: NextRequest) {
|
|||
);
|
||||
}
|
||||
const res = await fetch(
|
||||
`${req.nextUrl.origin}/api/v1/stock-quick-draft/add-line`,
|
||||
`${upstreamOrigin(req)}/api/v1/stock-quick-draft/add-line`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
|
|
@ -5797,7 +5839,7 @@ export async function POST(req: NextRequest) {
|
|||
|
||||
if (toolName === "stock_quick_draft.suppliers") {
|
||||
const res = await fetch(
|
||||
`${req.nextUrl.origin}/api/v1/stock-quick-draft/suppliers`,
|
||||
`${upstreamOrigin(req)}/api/v1/stock-quick-draft/suppliers`,
|
||||
{
|
||||
method: "GET",
|
||||
headers: { authorization: `Bearer ${process.env.AGENT_API_KEY ?? ""}` },
|
||||
|
|
@ -5832,7 +5874,7 @@ export async function POST(req: NextRequest) {
|
|||
if (!Array.isArray(args.items) || args.items.length === 0) {
|
||||
throw new Error("delivery_notes.create requires a non-empty items array.");
|
||||
}
|
||||
const res = await fetch(`${req.nextUrl.origin}/api/v1/delivery-notes`, {
|
||||
const res = await fetch(`${upstreamOrigin(req)}/api/v1/delivery-notes`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
|
|
@ -5856,7 +5898,7 @@ export async function POST(req: NextRequest) {
|
|||
if (toolName === "delivery_notes.cancel") {
|
||||
if (!args.id) throw new Error("Missing id for delivery_notes.cancel.");
|
||||
const res = await fetch(
|
||||
`${req.nextUrl.origin}/api/v1/delivery-notes/${encodeURIComponent(args.id)}/cancel`,
|
||||
`${upstreamOrigin(req)}/api/v1/delivery-notes/${encodeURIComponent(args.id)}/cancel`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
|
|
@ -5880,7 +5922,7 @@ export async function POST(req: NextRequest) {
|
|||
if (toolName === "delivery_notes.mark_invoiced") {
|
||||
if (!args.id) throw new Error("Missing id for delivery_notes.mark_invoiced.");
|
||||
const res = await fetch(
|
||||
`${req.nextUrl.origin}/api/v1/delivery-notes/${encodeURIComponent(args.id)}/mark-invoiced`,
|
||||
`${upstreamOrigin(req)}/api/v1/delivery-notes/${encodeURIComponent(args.id)}/mark-invoiced`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: { authorization: `Bearer ${process.env.AGENT_API_KEY ?? ""}` },
|
||||
|
|
@ -5896,7 +5938,7 @@ export async function POST(req: NextRequest) {
|
|||
if (toolName === "delivery_notes.mark_complete") {
|
||||
if (!args.id) throw new Error("Missing id for delivery_notes.mark_complete.");
|
||||
const res = await fetch(
|
||||
`${req.nextUrl.origin}/api/v1/delivery-notes/${encodeURIComponent(args.id)}/mark-complete`,
|
||||
`${upstreamOrigin(req)}/api/v1/delivery-notes/${encodeURIComponent(args.id)}/mark-complete`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: { authorization: `Bearer ${process.env.AGENT_API_KEY ?? ""}` },
|
||||
|
|
@ -5912,7 +5954,7 @@ export async function POST(req: NextRequest) {
|
|||
if (toolName === "delivery_notes.regenerate_pdf") {
|
||||
if (!args.id) throw new Error("Missing id for delivery_notes.regenerate_pdf.");
|
||||
const res = await fetch(
|
||||
`${req.nextUrl.origin}/api/v1/delivery-notes/${encodeURIComponent(args.id)}/regenerate-pdf`,
|
||||
`${upstreamOrigin(req)}/api/v1/delivery-notes/${encodeURIComponent(args.id)}/regenerate-pdf`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: { authorization: `Bearer ${process.env.AGENT_API_KEY ?? ""}` },
|
||||
|
|
@ -5928,7 +5970,7 @@ export async function POST(req: NextRequest) {
|
|||
if (toolName === "delivery_notes.create_quote") {
|
||||
if (!args.id) throw new Error("Missing id for delivery_notes.create_quote.");
|
||||
const res = await fetch(
|
||||
`${req.nextUrl.origin}/api/v1/delivery-notes/${encodeURIComponent(args.id)}/create-quote`,
|
||||
`${upstreamOrigin(req)}/api/v1/delivery-notes/${encodeURIComponent(args.id)}/create-quote`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: { authorization: `Bearer ${process.env.AGENT_API_KEY ?? ""}` },
|
||||
|
|
@ -5947,7 +5989,7 @@ export async function POST(req: NextRequest) {
|
|||
throw new Error("Missing customer_po for delivery_notes.set_customer_po.");
|
||||
}
|
||||
const res = await fetch(
|
||||
`${req.nextUrl.origin}/api/v1/delivery-notes/${encodeURIComponent(args.id)}/customer-po`,
|
||||
`${upstreamOrigin(req)}/api/v1/delivery-notes/${encodeURIComponent(args.id)}/customer-po`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
|
|
@ -5970,7 +6012,7 @@ export async function POST(req: NextRequest) {
|
|||
throw new Error("quantity must be > 0 for delivery_notes.set_item_quantity.");
|
||||
}
|
||||
const res = await fetch(
|
||||
`${req.nextUrl.origin}/api/v1/delivery-notes/items/${encodeURIComponent(args.id)}/quantity`,
|
||||
`${upstreamOrigin(req)}/api/v1/delivery-notes/items/${encodeURIComponent(args.id)}/quantity`,
|
||||
{
|
||||
method: "PATCH",
|
||||
headers: {
|
||||
|
|
@ -5994,7 +6036,7 @@ export async function POST(req: NextRequest) {
|
|||
);
|
||||
}
|
||||
const res = await fetch(
|
||||
`${req.nextUrl.origin}/api/v1/delivery-notes/combine`,
|
||||
`${upstreamOrigin(req)}/api/v1/delivery-notes/combine`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
|
|
|
|||
Loading…
Reference in a new issue