chore(deps): pin @decocms/start to 5.3.0 stable + promote next to 1.15.0#52
Merged
Conversation
Unlocks the operation API on `createInstrumentedFetch` (init.operation / defaultOperation / resolveOperation) shipped in deco-start PR #179, which the upcoming VTEX + Shopify URL routers and per-call operation overrides in this PR depend on. - devDep: ^2.5.0 -> 5.3.0-rc.0 (exact pin to the rc we're validating) - peerDep: >=0.19.0 -> >=5.3.0-rc.0 (consumers must opt into the rc before installing the @decocms/apps next channel that depends on it) Co-authored-by: Cursor <cursoragent@cursor.com>
Pure `(url, method) => operation | undefined` function pluggable into
`createInstrumentedFetch`'s `resolveOperation` option (shipped in
@decocms/start 5.3.0-rc.0). The resolved string becomes the span suffix
(`vtex.<operation>`), the `fetch.operation` span attribute, and the
histogram label downstream — so it's deliberately low-cardinality and
stable across deploys.
Covers the VTEX API surface this repo actually exercises:
- Intelligent Search (product_search, facets, top_searches, suggestions,
correction, banners, autocomplete) — endpoint becomes the suffix
- Checkout / orderForm — POST/PATCH/DELETE on `/items` are differentiated
into add / update / remove; coupons, profile, shippingData, paymentData,
simulation, regions, postal-code are split off; the singleton
orderForm/{id} root distinguishes GET vs PATCH
- Sessions (get vs update by method), segments
- Catalog System — pagetype, crossselling.{type}, products.variations,
products.search, facets.search, category.tree, sku, specification,
brand, falls back to catalog.other
- Masterdata (entity name encoded into the operation suffix)
- OMS (orders, orders.cancel, orders.pvt)
- VTEX ID (logout, authentication.start/validate, user, vtexid.other)
- IO GraphQL (POST to `_v/private/graphql/v1`), IO segment, sitemap.xml,
events, license-manager
22 vitest cases cover the matchers + edge cases (unparseable URLs,
case-insensitive methods, query-string stripping, fallback to
`undefined`). Callers that need finer granularity than the URL can
express (same URL, semantically different ops) override per-call via
`init.operation`, which always wins over the router.
Co-authored-by: Cursor <cursoragent@cursor.com>
Adds two paired primitives for Shopify outbound observability:
- `shopify/utils/operationRouter.ts` — same shape as the VTEX router;
pluggable into `createInstrumentedFetch.resolveOperation`. Maps the
storefront / admin GraphQL endpoints to `storefront.graphql` /
`admin.graphql` and covers the small REST surface (products, orders,
customers, inventory, checkouts, cart).
- `shopify/utils/graphqlOperationName.ts` — extracts the semantic
operation name from a GraphQL document (`query Foo { ... }` →
`"Foo"`). Strips block strings, string literals, and `# comments`
before matching so `query` / `mutation` / `subscription` keywords
inside docstrings/comments don't false-positive. Returns
`undefined` for anonymous or multi-operation documents (caller must
disambiguate via explicit name).
Wired into `createGraphqlClient` so every Shopify GraphQL call stamps
`init.operation = <OperationName>` on the outbound fetch. The
framework reads it via the operation API shipped in @decocms/start
5.3.0-rc.0 and produces spans named `shopify.<OperationName>` (e.g.
`shopify.ProductDetails`) instead of the generic
`shopify.storefront.graphql`. The URL router still applies as a
fallback when the extractor can't derive a name.
33 vitest cases cover both helpers including comment/string handling
and a real-world Shopify storefront query shape.
Co-authored-by: Cursor <cursoragent@cursor.com>
Pre-wired `InstrumentedFetch` factories that bundle the three pieces sites would otherwise have to assemble by hand: 1. `createInstrumentedFetch` from @decocms/start (spans, traceparent injection, URL redaction, cache-header span attributes). 2. The provider's URL router as `resolveOperation`, so unannotated callsites still get semantic span operations + histogram labels. 3. An `onComplete` callback that records every call into the `commerce_request_duration_ms` histogram via the meter configured by `instrumentWorker(...)`. Labels: `provider`, `operation`, `status_code`, `cached`. Sites opt in with one line at startup: setVtexFetch(createVtexFetch()); setShopifyFetch(createShopifyFetch()); `disableHistogram: true` opts out of metric emission while keeping spans + logs. `baseFetch` lets callers wrap a custom fetch (cookie passthrough, retry, proxy) and add instrumentation on top. Both factories + the underlying URL routers are re-exported from `@decocms/apps/vtex` and `@decocms/apps/shopify` for site consumption. `extractGraphqlOperationName` is also exposed so sites can name their own GraphQL clients consistently. 10 vitest cases cover the wiring: histogram emission with correct labels, URL-router operation propagation, explicit `init.operation` overrides, `x-cache: HIT` -> `cached=true`, status code propagation, `disableHistogram` opt-out, and stripping `operation` from the init before it reaches `baseFetch`. Co-authored-by: Cursor <cursoragent@cursor.com>
Routes all server-side ad-hoc fetches in vtex/ through the `setVtexFetch`-controlled `_fetch` instead of raw `globalThis.fetch`, so sites that opt into the instrumented factory (`createVtexFetch()`) get spans + commerce_request_duration_ms metrics + traceparent injection on every outbound VTEX call. Adds two API surface widenings on `vtex/client.ts`: - `setVtexFetch` now accepts `typeof fetch | InstrumentedFetch` (was `typeof fetch`). A plain fetch still works for uninstrumented test/dev setups; an `InstrumentedFetch` unlocks `init.operation` propagation. - New `getVtexFetch(): InstrumentedFetch` accessor for callsites that can't shape themselves into the `vtexFetch*` helpers — FormData uploads, .aspx legacy endpoints, generic proxies, etc. Callers stamp a per-call operation string via `init.operation`. - `vtexFetchResponse / vtexFetch / vtexCachedFetch / vtexFetchWithCookies` init parameter widened to `InstrumentedFetchInit` so `operation` flows through them too. Migrated callsites with explicit operations: - `vtex/utils/authHelpers.ts` performVtexLogout -> vtexid.logout - `vtex/utils/proxy.ts` proxyToVtex -> URL-router - `vtex/utils/proxy.ts` createVtexCheckoutProxy -> URL-router - `vtex/actions/misc.ts` notifyMe (AviseMe.aspx) -> notifyme - `vtex/actions/misc.ts` sendEvent (sp.vtex.com) -> analytics.event - `vtex/actions/newsletter.ts` subscribe -> newsletter.subscribe - `vtex/actions/analytics/sendEvent.ts` IS event -> analytics.event - `vtex/actions/profile.ts` updateProfileFromRequest -> io.graphql.UpdateProfile - `vtex/actions/masterData.ts` uploadAttachment -> masterdata.attachment.upload Untouched (intentional): - Client-side React hooks (`vtex/hooks/use*.ts`) — they run in the browser against same-origin `/api/...` which is proxied by `proxyToVtex` / `createVtexCheckoutProxy` on the server, so they inherit observability from the proxy span. Wiring an instrumented fetch in the browser yields no tracer / no metrics — wasted layer. - `resend/actions/send.ts`, `website/loaders/fonts/googleFonts.ts` — non-VTEX hosts, low traffic; left as raw fetch for now to keep PR scope focused. Tracked as follow-ups in observability docs. Co-authored-by: Cursor <cursoragent@cursor.com>
- Recipe in the Setup section shows the one-liner each (`createVtexFetch()` / `createShopifyFetch()`) plus the rc-version requirement on `@decocms/start@>=5.3.0-rc.0`. - Subpath table now lists the new barrel exports (`createVtexFetch`, `vtexOperationRouter`, `createShopifyFetch`, `shopifyOperationRouter`, `extractGraphqlOperationName`, `getVtexFetch`). - knip.json: drop `@decocms/start` from `ignoreDependencies` — it's now an actively-imported peer dep (was a knip workaround when the package was only referenced in JSDoc). Co-authored-by: Cursor <cursoragent@cursor.com>
feat(observability): URL routers + per-call operation names + commerce histograms
The two failing cases in `client-segment-cookie.test.ts` had been
silently broken since the test was first written — they pass the
default NOOP `RequestStore` so `RequestContext.current` returns null
inside the test callback and the production code never sees the
cookie under test. The five passing cases happen to expect
`headers.cookie === undefined`, which the broken setup also produces,
masking the bug. The release pipeline on `next` finally caught it
because the merged observability work bumped the Node target enough
that another spec wedged the runner into surfacing all failures
instead of one.
There are two compounding issues:
1. `new Request(url, { headers: { cookie } })` silently drops the
`cookie` header under Node 22 / undici because the Request
headers guard is "request", which strips forbidden request
headers. The cookie never reached `request.headers.get("cookie")`.
2. `RequestContext` is backed by a `RequestStore` that defaults to
a NOOP. The ALS-backed store is wired only at worker boot in
site code; in unit tests the run callback executes without any
context propagation, so `RequestContext.current` returns null.
Fix replaces the `RequestContext.run(new Request(...))` fixture with
a fresh `Headers` (which uses the "none" guard, so `set("cookie", ...)`
works) wrapped in a minimal Ctx-shaped object, and overrides the
`RequestContext.current` getter via `vi.spyOn`. The spy is restored
after `fn` resolves to keep tests isolated. No reliance on undici
internals or ALS plumbing.
Result: 413/413 tests pass. Unblocks the Release pipeline on `next`,
which runs `npm test` before `npx semantic-release` and was failing
on the post-merge run of PR #48 (the observability work).
Co-authored-by: Cursor <cursoragent@cursor.com>
fix(test): unbreak vtex_segment cookie-forward tests on Node 22
5.3.0-rc.0 (currently pinned) and 5.3.0-rc.1 were both deprecated upstream because they carried PR #164's framework-agnostic-entrypoints refactor, which duplicated module-level state across bundled entries (loaders 404'd, direct-POST observability channels no-op'd). Upstream reverted on main (@decocms/start@5.2.2) and re-applied the o11y stack on the src/-exports baseline as 5.3.0-rc.2. Substantive deltas the o11y operations work in this branch depends on (createVtexFetch / createShopifyFetch / fetchWithCache wiring) are preserved in rc.2 — the o11y API surface (instrumentWorker, withTracing, recordCacheMetric, injectTraceContext, createOtlpHttpMeterAdapter, createOtlpHttpErrorLogAdapter) is identical between rc.0 and rc.2. Typecheck + 413 vitest tests pass against rc.2. Drops the `next: >=15.0.0` peer (Next.js entrypoint was reverted from @decocms/start). apps-start never imported from @decocms/start/next so no source changes needed. Co-authored-by: Cursor <cursoragent@cursor.com>
PR #50 (chore(deps): bump @decocms/start to 5.3.0-rc.2) shipped with a truncated lockfile produced via `npm install --legacy-peer-deps`. The legacy-peer-deps flag was a workaround for a local registry config issue (a global npmrc pointing at npm.pkg.github.com/bawclothing/ was intercepting public-package fetches), not because of a real peer-dep conflict. The truncated lockfile passed local `npm test` (which doesn't require a complete tree for resolved test deps) but blocked the Release workflow's `npm ci` — strict-frozen install that fails on any missing transitive package — so semantic-release never ran and 1.15.0-next.2 was not cut. This commit regenerates the lockfile with the public registry forced (`npm_config_registry=https://registry.npmjs.org/ npm install`), restoring 504 packages and the full transitive tree. typecheck + 413 vitest tests pass against rc.2. Co-authored-by: Cursor <cursoragent@cursor.com>
@decocms/start@5.3.0 was promoted to @latest in decocms/deco-start#184 (o11y RC stack rebased onto the post-revert src/-exports baseline). Bump the peer/dev pins from 5.3.0-rc.2 to 5.3.0 so semantic-release on main cuts @decocms/apps@1.15.0 against the stable framework. Verified locally: - npm install resolves @decocms/start@5.3.0 (registry override required; global .npmrc still points at the bawclothing GH Packages registry). - npm run typecheck clean. - npm test 413/413 passing. Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
No issues found across 26 files
Tip: cubic can generate docs of your entire codebase and keep them up to date. Try it here.
Re-trigger cubic
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Promotes the entire `next` channel content (feat commits 1.15.0-next.{1,2}) plus a pin bump from `5.3.0-rc.2` → `5.3.0` into `main`, so semantic-release on `main` cuts `@decocms/apps@1.15.0` against the freshly-promoted `@decocms/start@5.3.0` stable framework.
Changes
npm_config_registry=https://registry.npmjs.org/is forced)Commits being promoted from `next`
Merge strategy
Merge commit (preserve history) so semantic-release sees the `feat:` commits and bumps `MINOR` → `1.15.0`. A squash would collapse to `chore:` and skip the release.
Verified locally
Known risk
CI publish historically fails for this repo with `404 PUT @decocms%2fapps` — the GH Actions `NPM_TOKEN` lacks `@decocms` publish scope. If that's still the case post-merge, the publish will need to be done manually with a personal token (same workaround used for `1.15.0-next.2`).
Made with Cursor
Summary by cubic
Pins
@decocms/startto 5.3.0 stable and promotes thenextchannel to cut@decocms/apps@1.15.0. Adds pre-wired VTEX and Shopify fetch instrumentation with URL routing and GraphQL operation names for clearer spans and metrics.New Features
createVtexFetch,vtexOperationRouter, andgetVtexFetch; routes server-side VTEX calls through the configured fetch and recordscommerce_request_duration_ms.createShopifyFetch,shopifyOperationRouter, andextractGraphqlOperationName; GraphQL client stampsinit.operationso spans readshopify.<OperationName>.Migration
@decocms/start@>=5.3.0.setVtexFetch(createVtexFetch())andsetShopifyFetch(createShopifyFetch()).Written for commit 7a92fd1. Summary will update on new commits. Review in cubic