Skip to content

chore(deps): pin @decocms/start to 5.3.0 stable + promote next to 1.15.0#52

Merged
vibe-dex merged 12 commits into
mainfrom
chore/pin-deco-start-5.3.0
May 19, 2026
Merged

chore(deps): pin @decocms/start to 5.3.0 stable + promote next to 1.15.0#52
vibe-dex merged 12 commits into
mainfrom
chore/pin-deco-start-5.3.0

Conversation

@vibe-dex
Copy link
Copy Markdown
Contributor

@vibe-dex vibe-dex commented May 19, 2026

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

  • `peerDependencies['@decocms/start']`: `>=5.3.0-rc.2` → `>=5.3.0`
  • `devDependencies['@decocms/start']`: `5.3.0-rc.2` → `5.3.0`
  • `package-lock.json` refreshed (registry override required; global `.npmrc` points at the bawclothing GH Packages registry, so locally npm_config_registry=https://registry.npmjs.org/ is forced)

Commits being promoted from `next`

  • `feat(vtex): add URL-derived operation router for outbound fetches`
  • `feat(shopify): URL router + GraphQL operation-name extraction`
  • `feat(vtex,shopify): createVtexFetch / createShopifyFetch factories`
  • `refactor(vtex): funnel server-side fetches through configured _fetch`
  • `docs(readme): document createVtexFetch / createShopifyFetch wiring`
  • `fix(test): unbreak vtex_segment cookie-forward tests on Node 22`
  • `chore(deps): bump @decocms/start` series (rc.0 → rc.2 → 5.3.0)

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

  • `npm install` resolves `@decocms/start@5.3.0`
  • `npm run typecheck` clean
  • `npm test` 413/413 passing

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/start to 5.3.0 stable and promotes the next channel 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

    • VTEX: createVtexFetch, vtexOperationRouter, and getVtexFetch; routes server-side VTEX calls through the configured fetch and records commerce_request_duration_ms.
    • Shopify: createShopifyFetch, shopifyOperationRouter, and extractGraphqlOperationName; GraphQL client stamps init.operation so spans read shopify.<OperationName>.
    • Docs/tests: README wiring guide; new unit tests; fixes VTEX segment-cookie tests on Node 22.
  • Migration

    • Requires @decocms/start@>=5.3.0.
    • To enable instrumentation: setVtexFetch(createVtexFetch()) and setShopifyFetch(createShopifyFetch()).

Written for commit 7a92fd1. Summary will update on new commits. Review in cubic

vibe-dex and others added 12 commits May 18, 2026 18:46
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>
@vibe-dex vibe-dex requested a review from a team May 19, 2026 18:41
@vibe-dex vibe-dex merged commit 5f964cb into main May 19, 2026
1 check passed
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant