Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 15 additions & 9 deletions vtex/actions/cart/addItems.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export interface Item {
export interface Props {
orderItems: Item[];
allowedOutdatedData?: Array<"paymentData">;
sc?: string;
}
Comment on lines 16 to 20
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

cat -n vtex/actions/cart/addItems.ts

Repository: deco-cx/apps

Length of output: 2284


🏁 Script executed:

fd . vtex/actions/cart -type f -name "*.ts" | head -20

Repository: deco-cx/apps

Length of output: 226


🏁 Script executed:

fd . vtex/actions/cart -type f -name "*.ts"

Repository: deco-cx/apps

Length of output: 226


🏁 Script executed:

git ls-files vtex/actions/cart/*.ts

Repository: deco-cx/apps

Length of output: 627


🏁 Script executed:

cat -n vtex/actions/cart/simulation.ts

Repository: deco-cx/apps

Length of output: 1796


🏁 Script executed:

rg -n "sc\?" vtex/actions/cart -A1 -B1

Repository: deco-cx/apps

Length of output: 365


🏁 Script executed:

rg -n "sc:" vtex/actions/cart -B2 -A2

Repository: deco-cx/apps

Length of output: 4285


🏁 Script executed:

cat -n vtex/utils/segment.ts | head -50

Repository: deco-cx/apps

Length of output: 1586


🏁 Script executed:

rg -n "interface Segment" vtex/utils/types.ts -A20

Repository: deco-cx/apps

Length of output: 778


🏁 Script executed:

rg -n "salesChannel" vtex/mod.ts -B5 -A5

Repository: deco-cx/apps

Length of output: 1017


🏁 Script executed:

rg -n "export interface Props" vtex/actions/cart -A10 | grep -E "(interface Props|sc\?)"

Repository: deco-cx/apps

Length of output: 994


Align sc type across cart actions to avoid type inconsistencies.

sc is typed as string in addItems.ts but simulation.ts accepts sc?: number. Both fallback to segment?.payload.channel (which is string). Standardizing to string | number with explicit String(...) coercion on send would prevent callers from hitting type errors when using similar actions with numeric values.

♻️ Suggested normalization
 export interface Props {
   orderItems: Item[];
   allowedOutdatedData?: Array<"paymentData">;
-  sc?: string;
+  sc?: string | number;
 }
@@
-        sc: sc ?? segment?.payload.channel,
+        sc: sc != null ? String(sc) : segment?.payload.channel,
🤖 Prompt for AI Agents
In `@vtex/actions/cart/addItems.ts` around lines 16 - 20, The Props interface's sc
field is currently typed inconsistently (sc?: string in the Props interface in
addItems.ts vs sc?: number in simulation.ts); change sc's type in the Props
interface to sc?: string | number to match across cart actions, and ensure any
place that sends sc (e.g., where the request payload is built / send call)
coerces it with String(sc) before transmission so callers can pass numeric or
string values without type errors; update any related usages of Props/sc to
accept the union type.


/**
Expand All @@ -29,28 +30,33 @@ const action = async (
ctx: AppContext,
): Promise<OrderForm> => {
const { vcsDeprecated } = ctx;
const {
orderItems,
allowedOutdatedData = ["paymentData"],
} = props;
const { orderItems, allowedOutdatedData = ["paymentData"], sc } = props;
const { orderFormId } = parseCookie(req.headers);
const cookie = req.headers.get("cookie") ?? "";
const segment = getSegmentFromBag(ctx);

try {
const response = await vcsDeprecated
["POST /api/checkout/pub/orderForm/:orderFormId/items"]({
const response = await vcsDeprecated[
"POST /api/checkout/pub/orderForm/:orderFormId/items"
](
{
orderFormId,
allowedOutdatedData,
sc: segment?.payload.channel,
}, {
sc:
sc ? sc :
(ctx.allowMixedSegments
? segment?.payload.channel
: ctx.salesChannel),
},
Comment thread
coderabbitai[bot] marked this conversation as resolved.
{
body: { orderItems },
headers: {
"content-type": "application/json",
accept: "application/json",
cookie,
},
});
},
);

proxySetCookie(response.headers, ctx.response.headers, req.url);

Expand Down
22 changes: 16 additions & 6 deletions vtex/actions/cart/getInstallment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { getSegmentFromBag } from "../../utils/segment.ts";

export interface Props {
paymentSystem: number;
sc?: string;
}

/**
Expand All @@ -19,16 +20,25 @@ const action = async (
ctx: AppContext,
): Promise<InstallmentOption> => {
const { vcsDeprecated } = ctx;
const { paymentSystem } = props;
const { paymentSystem, sc } = props;
const { orderFormId } = parseCookie(req.headers);
const cookie = req.headers.get("cookie") ?? "";
const segment = getSegmentFromBag(ctx);

const response = await vcsDeprecated
["GET /api/checkout/pub/orderForm/:orderFormId/installments"](
{ orderFormId, paymentSystem, sc: segment?.payload.channel },
{ headers: { accept: "application/json", cookie } },
);
const response = await vcsDeprecated[
"GET /api/checkout/pub/orderForm/:orderFormId/installments"
](
{
orderFormId,
paymentSystem,
sc:
sc ? sc :
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Using a truthy check for sc changes behavior vs the previous nullish fallback. If callers pass an explicit but falsy value (e.g., empty string), it will now be ignored and replaced by the fallback channel. Preserve nullish-coalescing semantics to avoid unintended channel overrides.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At vtex/actions/cart/getInstallment.ts, line 35:

<comment>Using a truthy check for `sc` changes behavior vs the previous nullish fallback. If callers pass an explicit but falsy value (e.g., empty string), it will now be ignored and replaced by the fallback channel. Preserve nullish-coalescing semantics to avoid unintended channel overrides.</comment>

<file context>
@@ -32,8 +32,10 @@ const action = async (
       sc:
-        sc ??
-        (ctx.allowMixedSegments ? segment?.payload.channel : ctx.salesChannel),
+        sc ? sc :
+        (ctx.allowMixedSegments
+          ? segment?.payload.channel
</file context>
Suggested change
sc ? sc :
sc ??
(ctx.allowMixedSegments
? segment?.payload.channel
: ctx.salesChannel)
Fix with Cubic

(ctx.allowMixedSegments
? segment?.payload.channel
: ctx.salesChannel)
},
{ headers: { accept: "application/json", cookie } },
);

proxySetCookie(response.headers, ctx.response.headers, req.url);

Expand Down
34 changes: 23 additions & 11 deletions vtex/actions/cart/removeItemAttachment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export interface Props {
content: Record<string, string>;
expectedOrderFormSections?: string[];
noSplitItem?: boolean;
sc?: string;
}

export const DEFAULT_EXPECTED_SECTIONS = [
Expand Down Expand Up @@ -48,23 +49,34 @@ const action = async (
content,
noSplitItem = true,
expectedOrderFormSections = DEFAULT_EXPECTED_SECTIONS,
sc,
} = props;
const { orderFormId } = parseCookie(req.headers);
const cookie = req.headers.get("cookie") ?? "";
const segment = getSegmentFromBag(ctx);

const response = await vcsDeprecated
["DELETE /api/checkout/pub/orderForm/:orderFormId/items/:index/attachments/:attachment"](
{ orderFormId, attachment, index, sc: segment?.payload.channel },
{
body: { content, noSplitItem, expectedOrderFormSections },
headers: {
accept: "application/json",
"content-type": "application/json",
cookie,
},
const response = await vcsDeprecated[
"DELETE /api/checkout/pub/orderForm/:orderFormId/items/:index/attachments/:attachment"
](
{
orderFormId,
attachment,
index,
sc:
sc ? sc :
(ctx.allowMixedSegments
? segment?.payload.channel
: ctx.salesChannel)
},
{
body: { content, noSplitItem, expectedOrderFormSections },
headers: {
accept: "application/json",
"content-type": "application/json",
cookie,
},
);
},
);

proxySetCookie(response.headers, ctx.response.headers, req.url);

Expand Down
35 changes: 24 additions & 11 deletions vtex/actions/cart/removeItems.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,32 +4,45 @@ import { parseCookie } from "../../utils/orderForm.ts";
import type { OrderForm } from "../../utils/types.ts";
import { getSegmentFromBag } from "../../utils/segment.ts";

export interface Props {
sc?: string;
}

/**
* @docs https://developers.vtex.com/docs/api-reference/checkout-api#post-/api/checkout/pub/orderForm/-orderFormId-/items/removeAll
* @title Remove Items from Cart
* @description Remove all items from the cart
*/
const action = async (
_props: unknown,
props: Props,
req: Request,
ctx: AppContext,
): Promise<OrderForm> => {
const { vcsDeprecated } = ctx;
const { sc } = props;
const { orderFormId } = parseCookie(req.headers);
const cookie = req.headers.get("cookie") ?? "";
const segment = getSegmentFromBag(ctx);

const response = await vcsDeprecated
["POST /api/checkout/pub/orderForm/:orderFormId/items/removeAll"](
{ orderFormId, sc: segment?.payload.channel },
{
headers: {
"content-type": "application/json",
accept: "application/json",
cookie,
},
const response = await vcsDeprecated[
"POST /api/checkout/pub/orderForm/:orderFormId/items/removeAll"
](
{
orderFormId,
sc:
sc ? sc :
(ctx.allowMixedSegments
? segment?.payload.channel
: ctx.salesChannel)
},
{
headers: {
"content-type": "application/json",
accept: "application/json",
cookie,
},
);
},
);

proxySetCookie(response.headers, ctx.response.headers, req.url);

Expand Down
9 changes: 7 additions & 2 deletions vtex/actions/cart/simulation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export interface Props {
postalCode: string;
country: string;
RnbBehavior?: 0 | 1;
sc?: string;
}

/**
Expand All @@ -27,15 +28,19 @@ const action = async (
): Promise<SimulationOrderForm> => {
const cookie = req.headers.get("cookie") ?? "";
const { vcsDeprecated } = ctx;
const { items, postalCode, country, RnbBehavior = 1 } = props;
const { items, postalCode, country, RnbBehavior = 1, sc } = props;
const segment = getSegmentFromBag(ctx);

const response = await vcsDeprecated[
"POST /api/checkout/pub/orderForms/simulation"
](
{
RnbBehavior,
sc: segment?.payload.channel,
sc:
sc ? sc :
(ctx.allowMixedSegments
? segment?.payload.channel
: ctx.salesChannel),
},
{
body: { items, country, postalCode },
Expand Down
20 changes: 15 additions & 5 deletions vtex/actions/cart/updateAttachment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export interface Props {
expectedOrderFormSections?: string[];
// deno-lint-ignore no-explicit-any
body: any;
sc?: string;
}

/**
Expand All @@ -26,6 +27,7 @@ const action = async (
attachment,
body,
expectedOrderFormSections = DEFAULT_EXPECTED_SECTIONS,
sc,
} = props;
const { orderFormId } = parseCookie(req.headers);

Expand All @@ -36,19 +38,27 @@ const action = async (
const cookie = req.headers.get("cookie") ?? "";
const segment = getSegmentFromBag(ctx);

const response = await vcsDeprecated
["POST /api/checkout/pub/orderForm/:orderFormId/attachments/:attachment"]({
const response = await vcsDeprecated[
"POST /api/checkout/pub/orderForm/:orderFormId/attachments/:attachment"
](
{
orderFormId,
attachment,
sc: segment?.payload.channel,
}, {
sc:
sc ? sc :
(ctx.allowMixedSegments
? segment?.payload.channel
: ctx.salesChannel),
},
{
body: { expectedOrderFormSections, ...body },
headers: {
accept: "application/json",
"content-type": "application/json",
cookie,
},
});
},
);

proxySetCookie(response.headers, ctx.response.headers, req.url);

Expand Down
21 changes: 15 additions & 6 deletions vtex/actions/cart/updateCoupons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { getSegmentFromBag } from "../../utils/segment.ts";

export interface Props {
text: string;
sc?: string;
}

/**
Expand All @@ -19,23 +20,31 @@ const action = async (
ctx: AppContext,
): Promise<OrderForm> => {
const { vcsDeprecated } = ctx;
const { text } = props;
const { text, sc } = props;
const cookie = req.headers.get("cookie") ?? "";
const { orderFormId } = parseCookie(req.headers);
const segment = getSegmentFromBag(ctx);

const response = await vcsDeprecated
["POST /api/checkout/pub/orderForm/:orderFormId/coupons"]({
const response = await vcsDeprecated[
"POST /api/checkout/pub/orderForm/:orderFormId/coupons"
](
{
orderFormId,
sc: segment?.payload.channel,
}, {
sc:
sc ? sc :
(ctx.allowMixedSegments
? segment?.payload.channel
: ctx.salesChannel),
},
{
body: { text },
headers: {
accept: "application/json",
"content-type": "application/json",
cookie,
},
});
},
);

proxySetCookie(response.headers, ctx.response.headers, req.url);

Expand Down
39 changes: 23 additions & 16 deletions vtex/actions/cart/updateItemAttachment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export interface Props {
content: Record<string, string>;
expectedOrderFormSections?: string[];
noSplitItem?: boolean;
sc?: string;
}

export const DEFAULT_EXPECTED_SECTIONS = [
Expand Down Expand Up @@ -48,28 +49,34 @@ const action = async (
content,
noSplitItem = true,
expectedOrderFormSections = DEFAULT_EXPECTED_SECTIONS,
sc,
} = props;
const { orderFormId } = parseCookie(req.headers);
const cookie = req.headers.get("cookie") ?? "";
const segment = getSegmentFromBag(ctx);

const response = await vcsDeprecated
["POST /api/checkout/pub/orderForm/:orderFormId/items/:index/attachments/:attachment"](
{
orderFormId,
attachment,
index,
sc: segment?.payload.channel,
const response = await vcsDeprecated[
"POST /api/checkout/pub/orderForm/:orderFormId/items/:index/attachments/:attachment"
](
{
orderFormId,
attachment,
index,
sc:
sc ? sc :
(ctx.allowMixedSegments
? segment?.payload.channel
: ctx.salesChannel),
},
Comment thread
devdaniloWicomm marked this conversation as resolved.
{
body: { content, noSplitItem, expectedOrderFormSections },
headers: {
accept: "application/json",
"content-type": "application/json",
cookie,
},
{
body: { content, noSplitItem, expectedOrderFormSections },
headers: {
accept: "application/json",
"content-type": "application/json",
cookie,
},
},
);
},
);

proxySetCookie(response.headers, ctx.response.headers, req.url);

Expand Down
Loading