STRATCONN-6824 [Braze] cart_updated ecommerce events + batch index fix - #3931
STRATCONN-6824 [Braze] cart_updated ecommerce events + batch index fix#3931joe-ayoub-segment wants to merge 8 commits into
Conversation
Combines the add/remove-from-cart ecommerce work with the batch
multistatus index fix (STRATCONN-6937):
- Add "Product Added"/"Product Removed" presets mapping Segment's
Product Added/Removed to ecommerce.cart_updated with action add/remove,
and exclude them from the Track Calls preset
- send(): attribute Braze errors on the sent-array index (payload.index),
skip payloads filtered by validate(), null-safe errors lookup
- per-item MultiStatus sent/body: sent = transformed event when actually
sent, body = { success: true } on 2xx / error.type on Braze error,
omit both when nothing was sent
- reconcile multistatus unit tests + add regression tests for
filtered-index attribution and a fully-successful batch
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Warning
Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.
This PR expands Braze ecommerce support by adding ecommerce.cart_updated (including add/remove presets) and enhancing batch MultiStatus handling to attribute per-item errors to the sent payload index while populating sent/body consistently.
Changes:
- Add
ecommerce.cart_updatedsupport (includingaction) plussubtotal_value,tax,shippingacross multiple ecommerce events. - Add
catalog_typesupport for single-product Product Viewed events (mapped to Brazeproperties.type). - Fix batch MultiStatus indexing and standardize
sent/bodypopulation for successes and per-item errors.
Reviewed changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/destination-actions/src/destinations/braze/index.ts | Updates presets and excludes Product Added/Removed from the generic Track Calls preset. |
| packages/destination-actions/src/destinations/braze/ecommerceSingleProduct/index.ts | Exposes catalog_type in the single-product action fields. |
| packages/destination-actions/src/destinations/braze/ecommerceSingleProduct/generated-types.ts | Adds typings/docs for catalog_type and new ecommerce fields in generated payload types. |
| packages/destination-actions/src/destinations/braze/ecommerceSingleProduct/tests/index.test.ts | Adds regression coverage for catalog_type and reformats existing assertions. |
| packages/destination-actions/src/destinations/braze/ecommerceSingleProduct/tests/snapshots/snapshot.test.ts.snap | Updates snapshots to reflect type/catalog trigger output. |
| packages/destination-actions/src/destinations/braze/ecommerce/types.ts | Enables Cart Updated event typing and adds new numeric fields + Product Viewed type. |
| packages/destination-actions/src/destinations/braze/ecommerce/generated-types.ts | Adds action, subtotal_value, tax, shipping to generated payload types. |
| packages/destination-actions/src/destinations/braze/ecommerce/functions.ts | Implements cart_updated payload shaping and batch MultiStatus index attribution + sent/body conventions. |
| packages/destination-actions/src/destinations/braze/ecommerce/fields.ts | Adds Cart Updated to choices, makes cart_id required for cart_updated, adds new fields and catalog_type. |
| packages/destination-actions/src/destinations/braze/ecommerce/constants.ts | Enables the CART_UPDATED constant. |
| packages/destination-actions/src/destinations/braze/ecommerce/tests/index.test.ts | Adds cart_updated tests and batch indexing regressions; updates MultiStatus expectations. |
| packages/destination-actions/src/destinations/braze/ecommerce/tests/snapshots/snapshot.test.ts.snap | Updates snapshots to reflect new fields and generated event selection. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| /** | ||
| * The cart action that was performed (add, remove, or replace). | ||
| */ | ||
| action?: string |
There was a problem hiding this comment.
This file is auto-generated from the action field definitions (// Generated file. DO NOT MODIFY IT BY HAND.). The type generator emits string for any field with choices — no generated-types.ts in this repo uses a string-literal union for a choice field. The runtime constraint is already enforced by the field's choices (validated by the framework), and the internal CartUpdatedEvent type in types.ts already narrows action to 'add' | 'remove' | 'replace'. Closing as not actionable.
| /** | ||
| * Required to use Braze catalog trigger features. Accepted values: price_drop, back_in_stock. | ||
| */ | ||
| catalog_type?: string[] |
There was a problem hiding this comment.
Same as the action field: this is an auto-generated file (// Generated file. DO NOT MODIFY IT BY HAND.). The type generator emits string[] for a multiple field with choices and cannot produce a literal-union array — no generated-types.ts in the repo does. The price_drop/back_in_stock contract is enforced at runtime by the field's choices. Closing as not actionable.
| subtotal_value?: number | ||
| tax?: number | ||
| shipping?: number |
There was a problem hiding this comment.
eslint/prettier pass clean on this file (the repo's config does not flag trailing whitespace here, and the same style is already present elsewhere in the file). No CI impact — closing as not actionable.
| }) | ||
|
|
||
| const errors = Array.isArray(response.data.errors) ? response.data.errors : [] | ||
| const errors = Array.isArray(response.data?.errors) ? response.data.errors : [] |
There was a problem hiding this comment.
The access is guarded by the Array.isArray(response.data?.errors) check immediately above, so it is runtime-safe and TypeScript narrows correctly here. Leaving as-is for now — closing as not actionable.
…ecommerce-cart-updated # Conflicts: # packages/destination-actions/src/destinations/braze/ecommerce/__tests__/index.test.ts # packages/destination-actions/src/destinations/braze/ecommerceSingleProduct/__tests__/index.test.ts
New required fields detectedWarning Your PR adds new required fields to an existing destination. Adding new required settings/mappings for a destination already in production requires updating existing customer destination configuration. Ignore this warning if this PR is for a new destination with no active customers in production. The following required fields were added in this PR:
Add these new fields as optional instead and assume default values in |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 12 out of 12 changed files in this pull request and generated no new comments.
Suppressed comments (3)
packages/destination-actions/src/destinations/braze/ecommerceSingleProduct/generated-types.ts:107
catalog_typeis documented as having accepted values (price_drop,back_in_stock), but the generated type allows anystring[]. If this file is meant to be authoritative for consumers, consider narrowing this to a string-literal union array (e.g.,('price_drop' | 'back_in_stock')[]) to prevent invalid values from compiling and to improve editor autocomplete.
catalog_type?: string[]
packages/destination-actions/src/destinations/braze/ecommerce/generated-types.ts:58
actionis constrained by the field choices (add/remove/replace) but is typed as a free-formstring. Aligning the type with the actual allowed values (string-literal union) will prevent invalid payloads from type-checking and reduce the need for casts downstream.
action?: string
packages/destination-actions/src/destinations/braze/ecommerce/fields.ts:661
- The input is named
catalog_typebut defaults from$.properties.type, and later gets emitted to Braze asproperties.type. This overloads a very generic Segment property name (type) and can easily collide with an existingproperties.typemeaning (e.g., product type/category). Consider changing the default path to something more explicit (e.g.,$.properties.catalog_type) while still emittingtypeto Braze, so existing Segment events withproperties.typedon’t get unintentionally reinterpreted as a Braze catalog trigger.
const catalog_type: InputField = {
label: 'Catalog Trigger Type',
description: 'Required to use Braze catalog trigger features. Accepted values: price_drop, back_in_stock.',
type: 'string',
multiple: true,
choices: [
{ label: 'Price Drop', value: 'price_drop' },
{ label: 'Back In Stock', value: 'back_in_stock' }
],
default: { '@path': '$.properties.type' },
Combines two pieces of Braze ecommerce work into a single PR (supersedes #3804 and #3929):
STRATCONN-6824 — add/remove from cart ecommerce events
ecommerce.cart_updatedevent, with anactionfield (add/remove/replace).subtotal_value,tax,shippingto cart_updated, checkout_started, order_placed and order_cancelled.catalog_type(price_drop/back_in_stock) to the single-product Product Viewed event.cart_idis conditionally required for cart_updated.Product Added/Product Removedevents tocart_updatedwithaction: 'add'/'remove', and are excluded from the Track Calls preset.STRATCONN-6937 — batch multistatus index fix + sent/body population
send()now attributes Braze per-item errors on the sent-array index (payload.index) rather than the original batch index, skips payloads filtered out byvalidate(), and readsresponse.data?.errorsnull-safely.MultiStatusResponsesent/bodyare populated per the repo convention:sent= the transformed event actually sent (omitted when nothing was sent),body={ success: true }on 2xx and the Brazeerror.typeon a per-item error.Testing
yarn cloud test --testPathPattern="braze/(ecommerce|ecommerceSingleProduct)"), plus the destination-level preset test.🤖 Generated with Claude Code