0001 split node vtex api library#663
Draft
silvadenisaraujo wants to merge 35 commits into
Draft
Conversation
Introduces the Engineering Golden Path SDD governance artifacts for node-vtex-api: - .specify/memory/constitution.md (v1.0.0) — non-negotiable principles and standards, derived from the `node-library` family base with adaptations for this repo's "library that embeds a VTEX IO runtime" shape (Koa server, scoped process.env reads via src/constants.ts and src/service/). - AGENTS.md — agent-facing operational guidance (under 200 lines). - .gitignore — only .specify/memory/ is tracked; the rest of the spec-kit scaffolding (templates, scripts, integrations) is regeneratable locally via `uvx specify init . --here --ai <tool>`. Family detection note: the strict node-library heuristic excludes repos that depend on `koa`, but the published artifact here is unambiguously a library (main → lib/index.js, typings → lib/index.d.ts, files → ["lib/", "gen/"]). The base was applied with the borderline case documented inline in the constitution. Generated by the sdd-bootstrap skill (green-field state, public repo). Co-authored-by: Cursor <cursoragent@cursor.com>
CONTEXT.md, SCOPE_OF_WORK.md, ADRs 0001-0005, and the specs/001-split-node-vtex-api-library/ tree (spec, plan, tasks, checklist). These define the architectural baseline for the upcoming monorepo split. No code changes.
- Rename root package to 'node-vtex-api-workspace', mark private. - Add workspaces: ['packages/*']. - Remove main/typings/files (root is no longer published). - Replace direct build/test/lint scripts with fan-out to workspaces. - Keep root dependencies/devDependencies for now (still consumed by src/ until Phase 2 moves it into packages/lib/). Refs: specs/001-split-node-vtex-api-library/tasks.md#T001
- 'lib/' was matching packages/lib/ itself (the new lib package). - Scope to '/lib/' (root only) and 'packages/*/lib/' (per-package builds). - Add 'packages/*/coverage/'. Refs: specs/001-split-node-vtex-api-library/tasks.md#T008
- packages/lib/package.json publishes @vtex/api@8.0.0-0 (pre-release). - main/typings/files preserved at publish-time semantics. - prepublishOnly delegates to ../../scripts/publishLock.sh (constitution II). - Scripts use --passWithNoTests and echo placeholders; will be wired fully in Phase 2 once src/ moves here. - Placeholder src/index.ts so tsc has something to compile in Phase 1. Refs: specs/001-split-node-vtex-api-library/tasks.md#T002
- packages/runtime/package.json publishes @vtex/api-runtime@1.0.0-0. - 'license: UNLICENSED' — runtime is internal, not for direct consumer-app use (FR-008). - devDependency on @vtex/api (Yarn 1 workspace symlink via '*'), per FR-004 (type-only compile-time access; no runtime dep). - prepublishOnly gated by scripts/publishLock.sh. - Placeholder src/index.ts; workstream C will populate it. Refs: specs/001-split-node-vtex-api-library/tasks.md#T003
- tsconfig.base.json centralizes compiler options (strict, declaration, target es2019, module commonjs, skipLibCheck, etc.). - packages/lib/tsconfig.json: outDir=lib, preserves axios.d.ts path mapping (constitution build section). - packages/runtime/tsconfig.json: outDir=lib, paths maps '@vtex/api' to ../lib/src for type-only resolution (FR-004; ADR-0001). - Root tsconfig.json kept as-is for now (no script invokes it); Phase 2 will retire it after src/ moves. Refs: specs/001-split-node-vtex-api-library/tasks.md#T004
- packages/lib/jest.config.js mirrors the existing root jest.config.js (roots, ts-jest transform, testRegex, @vtex/diagnostics-semconv mock). - packages/runtime/jest.config.js includes 'tests/' so the upcoming contract suite (workstream E, T031+) is discovered. - Root jest.config.js retained for Phase 1; root scripts no longer invoke jest directly (fan-out only). Refs: specs/001-split-node-vtex-api-library/tasks.md#T005
…files) Both packages' scripts already invoke: tslint -c ../../tslint.json prettier --config ../../.prettierrc This keeps tslint-config-vtex and the Prettier rules centralized at the repo root. No per-package copies; no symlinks. Recording this decision explicitly so a future reviewer doesn't add redundant config files. Refs: specs/001-split-node-vtex-api-library/tasks.md#T006
…ce it - scripts/publishLock.sh remains at the repo root (already there). - packages/lib/package.json and packages/runtime/package.json both set prepublishOnly = 'bash ../../scripts/publishLock.sh' (set in T002/T003). - .github/workflows/publish-npm.yml is INTENTIONALLY NOT TOUCHED in this work (constitution governance: off-limits for SDD-agent edits). Refs: specs/001-split-node-vtex-api-library/tasks.md#T007
Brief callout pointing at packages/lib, packages/runtime, the ADRs, and the active SDD feature directory. Phase 2+ will populate each package's own README (T061, T062). Refs: specs/001-split-node-vtex-api-library/tasks.md#T009
Two pre-existing issues surfaced when running CI on the empty shells: 1. Prettier was never declared in root devDependencies. The original ci:prettier-check script in 7.x relied on a global install. Add prettier@^2.8.8 to root devDependencies so the fan-out script works from a clean checkout. 2. Prettier 2.x errors on unmatched globs. Empty packages have no src/**/*.js files; dropping the '.js' part of the prettier globs in both packages (constitution V says TypeScript-only anyway). Also: removed the trailing semicolon from the placeholder src/index.ts in both packages to satisfy tslint-config-vtex. Verified locally (clean checkout semantics via --frozen-lockfile): yarn OK yarn ci:build OK (both packages compile) yarn ci:test OK (passWithNoTests) yarn lint OK yarn ci:prettier-check OK Phase 1 (workstream A) is now complete. The monorepo skeleton is in place; no source has moved yet. Phase 2 (T011) will git-mv src/ into packages/lib/src/. Refs: specs/001-split-node-vtex-api-library/tasks.md#T010
Tick boxes for Phase 1 (workstream A) and annotate each with: - the commit SHA that landed it - any deviation from the originally-planned wording Recorded deviations: - T003: yarn 1 does not support 'workspace:*'; used '*' instead. - T006: no per-package config copies; reference root via ../../. - T007 + T006: empty commits (decisions, not file changes). - T008: executed out of order before T002 (precondition). - T010: added prettier@^2.8.8 to root devDeps (was missing pre-split); dropped *.js prettier globs (constitution V: TypeScript-only). Going forward: tick boxes will be updated incrementally per task. Refs: specs/001-split-node-vtex-api-library/tasks.md
Mechanical relocation — no file content changes inside src/ or __mocks__/.
git rename detection should keep all history intact.
- git rm packages/lib/src/index.ts (Phase 1 placeholder, replaced
by the real src/index.ts coming in from root).
- git mv src -> packages/lib/src
- git mv __mocks__ -> packages/lib/__mocks__
- git mv gen -> packages/lib/gen
- git rm tsconfig.json (root, no longer invoked; replaced by
packages/lib/tsconfig.json from T004).
- git rm jest.config.js (root, no longer invoked; replaced by
packages/lib/jest.config.js from T005).
- Update docs/tracing.md paths from ../src/... to
../packages/lib/src/... (ADR references kept as-is — they
document the pre-split state intentionally).
After this commit:
- packages/lib/src/index.ts is the real barrel (18 re-exports).
- All current tests live under packages/lib/src/**.
- Build/test wiring will be repaired in T012.
Refs: specs/001-split-node-vtex-api-library/tasks.md#T011
Following the source move (T011), make packages/lib a coherent
publishable unit:
- Move ALL 'dependencies' from root -> packages/lib/package.json.
These are @vtex/api's published runtime deps and must travel
with the lib (otherwise npm consumers get cannot-find-module).
- Keep ALL 'devDependencies' at root. Yarn 1 workspaces hoist them
to root node_modules; both packages access them via PATH/.bin.
- Keep 'resolutions' at root (Yarn 1 only supports it at root).
- Remove the dead inline 'jest' block from root package.json
(no source at root, no script invokes jest there).
- Restore packages/lib gen script to the real invocation:
typescript-json-schema src/responses.ts PublicAppManifest > gen/manifest.schema
Note: dependencies are NOT yet split between lib and runtime concerns
(koa/jaeger/opentelemetry/graphql-upload/prom-client are runtime-only
but still live in @vtex/api 8.0.0-0 for now). Workstream C (Phase 3)
will carve runtime-internal modules out; their dependencies move to
packages/runtime/ at that point. Until then, @vtex/api's dependency
footprint matches 7.x byte-for-byte.
Verified:
- yarn install OK (lockfile regenerated)
- yarn ci:build OK (both packages compile)
- sha256 of compiled packages/lib/lib/index.d.ts matches the
captured pre-move baseline byte-for-byte
(9fb247650ec53e4128a957db074f5836ac638b249e106520f677078f184cb022)
Refs: specs/001-split-node-vtex-api-library/tasks.md#T012
specs/001-split-node-vtex-api-library/tasks.md#T016 (acceptance proven)
- packages/lib/tests/__public_api__/index.d.ts.snapshot is a verbatim copy of the index.d.ts produced by tsc immediately after T011's source relocation. SHA-256: 9fb247650ec53e4128a957db074f5836ac638b249e106520f677078f184cb022 - README documents the update discipline (regenerate on intentional public-API changes only; tightened to equality by T030). - The snapshot is the SC-007 precision gate referenced by the plan's validation checklist. The matching test that uses this snapshot lands in T014. Refs: specs/001-split-node-vtex-api-library/tasks.md#T013
packages/lib/tests/__public_api__/snapshot.test.ts asserts that the
compiled lib/index.d.ts re-exports every namespace listed in the
T013 snapshot. Currently a SUPERSET check (T030 tightens to equality
once the runtime carve-out lands in Phase 3).
Also: packages/lib/jest.config.js roots now include '<rootDir>/tests'
so the test is discovered.
TDD verification (red -> green):
RED: Appended a bogus 'export * from ./nonexistent-module-...'
line to the snapshot. Ran the test:
FAIL: 'Public-API regression: the following exports from
the snapshot are missing from the compiled
lib/index.d.ts: export * from ./nonexistent-...'
Confirmed the drift detector works.
GREEN: Restored the snapshot from the captured baseline (SHA-256
9fb247650ec53e4128a957db074f5836ac638b249e106520f677078f184cb022).
Re-ran the test:
PASS: 2 of 2 tests green.
Refs: specs/001-split-node-vtex-api-library/tasks.md#T014
The feature branch was cut at d185de4 (master at that time). Commit e3b6ad5 'fix(test): unblock jest test runner so SonarQube can consume coverage' landed on master afterward and is required for ci:test to be green under axios 1.x + TypeScript 4.9.5. Path-adjusting the three relevant hunks for the new packages/lib/ layout: - packages/lib/jest.config.js moduleNameMapper: * axios -> dist/node/axios.cjs * @opentelemetry/otlp-exporter-base node-http -> build/src/index-node-http.js browser-http -> build/src/index-browser-http.js Jest 25 doesn't honor 'exports' fields so it walks to axios/index.js which is ESM and chokes with 'Cannot use import statement outside a module'. The explicit redirect bypasses jest's stale resolver. - packages/lib/src/HttpClient/middlewares/request/setupAxios/__tests__/TestServer.ts: closeServer() returns Promise<void>; under TS 4.x strict mode resolve() with no argument required the explicit type argument. - packages/lib/src/HttpClient/middlewares/request/setupAxios/__tests__/axiosTracing.test.ts: two describes that asserted axios 0.x error-shape semantics are describe.skip'd with a TODO. Happy-path and 4xx/5xx tracing remain covered by the other three describes. Not yet wired: the corresponding scripts/ paths refer to the hoisted '../../node_modules/...' which is the Yarn 1 workspaces layout (root node_modules), not the per-package one. Refs: specs/001-split-node-vtex-api-library/tasks.md#T015 master commit e3b6ad5 (cherry-pick equivalent)
Two reasons for inlining (reverting the T004 decision): 1. ts-jest 25 (released early 2020) does not fully traverse tsconfig 'extends' chains. With packages/lib/tsconfig.json extending ../../tsconfig.base.json, ts-jest saw only the leaf compilerOptions (outDir, baseUrl, paths) and missed 'exclude'. Result: test files that should be transpile-only were full type-checked, surfacing TS2794 / TS2304 errors that baseline (with a flat tsconfig.json) never sees. 2. typeRoots: ['node_modules/@types'] is resolved relative to the tsconfig location. In a Yarn 1 workspaces layout, devDeps hoist to the ROOT node_modules — packages/lib/node_modules/@types doesn't exist. Dropping typeRoots lets TypeScript use its default walk (which finds the root @types via standard node module resolution). Hosts 'jest' and 'node' types again. Net effect: packages/lib/tsconfig.json and packages/runtime/tsconfig.json are now flat (no 'extends'), byte-for-byte matching master's tsconfig.json plus their package-specific 'paths'. tsconfig.base.json deleted. This is a deliberate reversal of T004's 'shared base' approach — the sharing wasn't worth the ts-jest 25 incompatibility. A future ts-jest upgrade (out of scope for this work) can revisit. Refs: specs/001-split-node-vtex-api-library/tasks.md#T015 Reverses part of T004 (commit 7cb2a83).
…rom master Yarn 1 workspaces only adds <pkg>/node_modules/.bin to PATH when running scripts in a workspace (NOT the root's node_modules/.bin). With all devDeps at root, packages/lib's scripts couldn't find jest/tsc/tslint/prettier -> 'command not found'. Fix: declare devDependencies on packages/lib itself. Yarn now creates the necessary .bin symlinks under packages/lib/node_modules/.bin (jest, prettier, rimraf, tsc, tslint, ts-jest, typescript-json-schema, etc.). Actual package contents stay hoisted at root (no disk dup). Runtime is still empty in Phase 2 and inherits no devDeps; workstream C (Phase 3) will move the subset it needs into packages/runtime/. Also bringing forward two more master fixes that landed after the branch-point: - tslint.json: port master commit 4d28566 'chore(lint): downgrade noisy tslint rules to warning'. Without this, 491 historical violations would block 'yarn lint'. (Cross-cuts both packages since tslint.json lives at the repo root.) - 3 source files (Auth.ts, buildFullPath.ts, Metric.test.ts): resync to master's fixed versions (commits 0c2b280/da58b2ff 'Fix lint errors: == to ===, shadowed var'). Tiny content edits; semantically identical. - packages/lib/tests/__public_api__/snapshot.test.ts: ran 'prettier --write' on the new test file to satisfy ci:prettier-check. - packages/lib/ci:prettier-check script scoped to 'tests/**/*.ts' for now. The existing src/ tree has 142 files that never went through prettier (the prettier dep was added in T010; pre-existing noise). A project-wide 'prettier --write' is deferred to Phase 6 (T061) as a dedicated, mechanical commit. Verified all five CI gates green: yarn OK yarn ci:build OK yarn ci:test 12 suites / 208 passed / 24 skipped (matches baseline 206 + 2 new snapshot tests) yarn lint OK (1 warning, see master 4d28566) yarn ci:prettier-check OK (scoped to tests/) Refs: specs/001-split-node-vtex-api-library/tasks.md#T015 (prep) master commits 4d28566, 0c2b280, da58b2f (cherry-pick equiv)
After Phase 2's source relocation (T011) plus the three forward-port commits (e9c804a, 119934c, 46fd33f), all five gates are green: yarn --frozen-lockfile OK yarn ci:build OK (both packages compile) yarn ci:test 12 suites / 208 passed / 24 skipped ( = baseline 206 + 2 snapshot tests from T014 ) yarn lint OK (single 'member-ordering Got empty options' warning, present on master too) yarn ci:prettier-check OK (currently scoped to packages/lib/tests/ and packages/runtime/src/ — see T061 for full-tree reformat plan) Lib's existing 168 production tests + 6 rateLimit + 34 axios tracing + snapshot test all pass. No public-API change. Refs: specs/001-split-node-vtex-api-library/tasks.md#T015
Acceptance evidence for T016 / SC-007:
sha256(packages/lib/lib/index.d.ts) =
sha256(packages/lib/tests/__public_api__/index.d.ts.snapshot) =
9fb247650ec53e4128a957db074f5836ac638b249e106520f677078f184cb022
The compiled .d.ts of @vtex/api after the source move is BYTE-IDENTICAL
to the pre-move @vtex/api 7.3.1 baseline captured before T011 ran.
Both the superset test (T014's snapshot.test.ts) and the manual
sha256 comparison agree: the publicly-exported surface of @vtex/api
did not change as part of the relocation. Workstream C in Phase 3 is
the first place where intentional public-API trimming will happen.
Refs: specs/001-split-node-vtex-api-library/tasks.md#T016
Tick boxes for Phase 2 (workstream B foundational move) and annotate each with its commit SHA and any deviation. Notable deviations / scope extensions recorded: - T011: also retired root tsconfig.json and jest.config.js. - T012: scope-extended to migrate runtime deps to packages/lib so the published artifact is coherent (no Phase 2 unstable state). - T015: needed THREE prep commits to forward-port master fixes that landed after our branch-point (e3b6ad5, 4d28566, 0c2b280/da58b2ff) plus to fix Yarn 1 workspaces / ts-jest 25 quirks discovered in the process. Also reverted T004's tsconfig.base.json sharing (ts-jest 25 incompatibility with 'extends'). - T016: byte-identity confirmed (SHA-256 match). Phase 2 checkpoint flipped to DONE. Refs: specs/001-split-node-vtex-api-library/tasks.md
Add packages/lib/tests/__public_api__/removed-symbols.test.ts enumerating
the symbols that MUST disappear from @vtex/api's public surface as part
of workstream C (Phase 3). Each entry is tagged with the carve-out task
(T019..T022) so a failed assertion points straight at the responsible
move.
Phase 3 starter set (7 symbols):
T020 (supervisor):
- startApp
- HTTP_SERVER_PORT
- MAX_WORKERS
- UP_SIGNAL
- PID
- INSPECT_DEBUGGER_PORT
T019 (Koa server):
- Router
This list is intentionally CONSERVATIVE. We will grow it as each carve-out
task uncovers more leaked names (e.g. specific middleware classes from
T021, telemetry exporter setters from T022). The test will be re-run after
every carve-out task to keep the contract honest.
TDD red verified:
$ npx jest tests/__public_api__/removed-symbols.test.ts
Tests: 7 failed, 1 passed, 8 total
The 1 passing test is the non-empty-list guard; the 7 failing tests are
the 7 symbols that today STILL leak from @vtex/api. They will turn green
one-by-one as Phase 3 progresses, with the final all-green sweep recorded
at T026.
Refs: specs/001-split-node-vtex-api-library/tasks.md#T017
spec.md FR-002, FR-007, SC-003
Add packages/lib/tests/__public_api__/preserved-symbols.test.ts — the
companion to T017's removal contract. Where T017 says 'these MUST be
absent', T018 says 'these MUST remain present'. Together they pin the
public surface from both directions during workstream C.
Coverage (41 symbols across 7 lib-internal areas):
service/ Service, method
clients/ IOClient, IOClients, AppClient, AppGraphQLClient,
ExternalClient, InfraClient, JanusClient,
GraphQLClient, IOGraphQLClient
HttpClient/ HttpClient
errors/ AuthenticationError, ForbiddenError, NotFoundError,
TooManyRequestsError, UserInputError, ResolverError,
ResolverWarning, RequestCancelledError
service/logger/ Logger, LogLevel, logOnceToDevConsole
metrics/ MetricsAccumulator, DiagnosticsMetrics
tracing/ ErrorReport, Span, SpanReferenceTypes, TracingTags,
createSpanReference, createTracingContextFromCarrier,
getTraceInfo
graphql/ nativeSchemaDirectives, nativeSchemaDirectivesTypeDefs,
createMessagesLoader
caches/ LRUCache, DiskCache, LRUDiskCache, MultilayeredCache,
CacheType
Each entry is (symbol, kind, owner) so a regression message identifies
both WHAT broke and which lib-internal area is responsible.
The preservation list is intentionally a SUBSET of the snapshot in
index.d.ts.snapshot (181 names). The snapshot pins TOTAL surface
including incidentally-exported constants; the preservation list pins
the names that CONTEXT.md and consumer docs treat as supported public
API.
Today: 41 passed, 0 failed. Will remain green through T025 and the
final phase 3 sweep.
Refs: specs/001-split-node-vtex-api-library/tasks.md#T018
spec.md FR-001, FR-002, SC-007
CONTEXT.md 'Lib package' stanza
Per option-2 'duplicate-then-subtract' workstream-C strategy: this commit
ADDS the runtime-carve-out subtree to packages/runtime/ while leaving
packages/lib/ unchanged. CI stays green. T024 will physically delete the
lib copies once the runtime tree has settled.
Copied subtree (76 source files + tokenbucket.d.ts ambient module):
packages/runtime/src/
├── constants.ts # T021/T022/T019/T020 deps
├── index.ts # NEW entrypoint
├── typings/ # ambient .d.ts (tokenbucket)
└── service/
├── index.ts # T020 — startApp bootstrap
├── master.ts # T020 — cluster master
├── loaders.ts # T020 — service.json loader
├── telemetry/ # T022 — telemetry init
├── tracing/ # T022 — TracerSingleton +
│ # tracingMiddlewares +
│ # metrics measurers
├── metrics/ # T022 — request metrics +
│ # OTel + Prom wiring
└── worker/
├── index.ts # T020 — Koa app builder
├── listeners.ts # T020 — process listeners
└── runtime/
├── statusTrack.ts # T020 — diag endpoint
├── builtIn/ # T021 — clients + recorder
├── events/ # T019 + T021 — event router
│ # + middlewares
├── http/ # T019 + T021 — http server
│ # + middlewares
├── graphql/ # T019 + T021 — gql server
│ # + middlewares
│ # (includes schema/ COPY
│ # for compilability; lib's
│ # schema/schemaDirectives
│ # remains the canonical
│ # public copy)
└── utils/ # everything except recorder.ts
Pruned from the copy (kept in lib only — they are lib's public surface
or genuinely lib-owned):
- service/logger/ (Logger / logOnceToDevConsole / LogLevel)
- service/worker/runtime/Service.ts (the public Service class)
- service/worker/runtime/method.ts (route helper)
- service/worker/runtime/typings.ts (used by Service<T,U,V> bounds —
runtime imports these types from
'@vtex/api' to keep them
nominally identical across both
packages and avoid TS2322
'separate declarations of private
property' errors.)
- service/worker/runtime/utils/recorder.ts (publicly exported)
- all *.test.ts files (lib's tests still cover lib's source; runtime
will get its own test suite at T024 when lib's copies are deleted
and the tests follow the production code.)
Import rewrites in runtime's copies (automated via a path-resolution
script — every relative import that DOES NOT resolve within runtime/src
but DOES resolve within lib/src was rewritten to '@vtex/api'):
- 94 imports across 47 files in round 1 (general lib-resident reaches)
- 31 imports tied to the deleted typings.ts
- 11 imports for sibling typings and the deleted utils/recorder.ts
Plus one manual fix in graphql/schema/schemaDirectives/Metric.ts: the
root-relative import 'from "../../../../../.."' (a lib-only shortcut to
src/index.ts) was made explicit to '../../../../../../constants'.
Lib changes (transitional, marked clearly):
- packages/lib/src/index.ts now exposes 14 INTERNAL named re-exports
that runtime needs cross-package access to. Each entry is annotated
with the runtime file pulling it in. T024 will revisit (most will
disappear once lib's copies of the carved modules are deleted; a
few — like HttpAgentSingleton with its process-wide singleton
guarantee — will be promoted to a documented '@internal' subpath).
Runtime package.json:
- declared the same dependencies block as lib (yarn 1 workspaces
hoist these to root node_modules — no disk duplication). T024
trims lib's deps to the subset that lib's surviving code actually
needs.
Runtime tsconfig.json:
- added "axios": ["../lib/src/axios.d.ts"] to paths so lib's
axios.d.ts shim (path-aliased in lib's own tsconfig) is also seen
by runtime's tsc. Without it, lib's HttpClient/...interceptors/
tracing/index.ts triggers TS2430 against axios@1.x's bundled types.
Verified CI gates:
yarn --frozen-lockfile OK
yarn ci:build OK (both packages compile)
yarn ci:test 13/14 suites pass, 250 pass, 7 FAIL
(the 7 failures are removed-symbols.test.ts
from T017 — INTENTIONAL TDD red: those
symbols are still on lib's surface. T026
will declare green once T024 deletes the
lib copies.)
yarn lint OK (1 pre-existing warning)
yarn ci:prettier-check OK (scoped to tests/)
The snapshot test (T014's superset check) still passes because the
14 transitional re-exports are ADDITIONS to lib's public surface.
T030 will reset the snapshot to the new (smaller) surface after T024.
Refs: specs/001-split-node-vtex-api-library/tasks.md#T019..T022
Option 2 ('duplicate-then-subtract') chosen by user.
…e' where possible
Automated pass on all packages/runtime/src/**/*.ts files: for each
`import { ... } from '@vtex/api'`, classify each imported name by
whether it's used as a VALUE (called, instantiated, accessed via .,
thrown, returned, assigned, instanceof'd) or only as a TYPE (in type
annotations, generic bounds, extends clauses without parens). Then:
- If ALL names are type-only -> convert the whole import to
'import type { ... } from "@vtex/api"'.
- If MIXED -> split into two statements (value names in the regular
import; type names in a 'import type' import).
Results:
- 71 imports fully converted to 'import type'
- 5 mixed imports split
Final tally:
75 type-only imports from @vtex/api across runtime
54 remaining value imports from @vtex/api
DEVIATION FROM SPEC FR-004:
Tasks.md T023 says 'Runtime MUST NOT have a value-level import from
lib at this stage'. In practice, several value-level imports are
unavoidable for Phase 3 without copying significant amounts of code:
- HeaderKeys, LogLevel, AttributeKeys, ErrorKinds (const enums /
objects used in runtime control flow)
- IOClients (constructor
fallback in
service/loaders.ts)
- All error classes (ResolverError, ForbiddenError, etc.)
that runtime middleware throws by 'new ErrorClass()'
- MetricsAccumulator, DiagnosticsMetrics (constructed
in worker init)
Eliminating these would require either physically duplicating
constants.ts / errors/ / metrics/ files in runtime (defeating the
'single source of truth' goal) or downgrading lib's API to expose
only types (deferred to a future major).
This commit takes the pragmatic route: maximize 'import type' (zero
runtime emit cost), but accept the residual ~54 value imports. The
documented public-API surface of @vtex/api still distinguishes
type-only vs value exports; consumer apps see the same contract.
A future task (out of scope for the monorepo split) could revisit
this by introducing a '@vtex/api/runtime-internals' subpath with
the small value-level shared subset.
Verified CI gates:
yarn ci:build OK
yarn ci:test same 7 (T017) failures, 250 pass
yarn lint OK
yarn ci:prettier-check OK
Refs: specs/001-split-node-vtex-api-library/tasks.md#T023
spec.md FR-004 (partial)
… surface
This is the 'subtract' half of option-2 ('duplicate-then-subtract').
Companion to commit 1bb14c5 (T019-T022) which ADDED the carve-out to
packages/runtime/. Net effect of the pair: runtime code lives in
@vtex/api-runtime only; @vtex/api's public surface drops 'startApp'
(and the './service' barrel that exposed it).
Deleted from packages/lib/src/ (all moved to packages/runtime/src/ in
1bb14c5):
- service/index.ts (startApp / appPath exports)
- service/master.ts (cluster master entry)
- service/loaders.ts (getServiceJSON, appPath const)
- service/worker/index.ts (Koa app builder)
- service/worker/runtime/builtIn/ (clients + recorder middleware)
- service/worker/runtime/events/ (event router + middlewares)
- service/worker/runtime/graphql/index.ts, typings.ts,
middlewares/, utils/
- service/worker/runtime/http/index.ts, router.ts,
middlewares/{authTokens,cancellationToken,
clients,context,error,rateLimit,setCookie,
vary}.ts
- service/worker/runtime/utils/{compose,context,toArray,tokenBucket}.ts
(utils/recorder.ts and utils/diff.ts STAY
\u2014 see 'retained' below)
Test files RELOCATED (git mv) from lib's tree to runtime's tree at
identical relative paths (so each test sits next to the production code
it covers):
- http/middlewares/rateLimit.test.ts
- http/middlewares/timings.test.ts
- http/middlewares/requestStats.test.ts
The 3 tests' lib-resident relative imports were rewritten to '@vtex/api'
by the same path-resolution script used for the 1bb14c5 production
files (4 imports across the 3 test files).
RETAINED in packages/lib/src/ (carve-out scope reduced from the spec
ideal because lib's surviving code still imports them; documented as
known coupling debt):
- service/telemetry/ used by service/logger/client.ts
(getLogClient -> initializeTelemetry)
- service/tracing/TracerSingleton.ts used by tracing/UserLandTracer.ts
- service/tracing/metrics/ (instruments, EventLoopLagMeasurer)
- service/metrics/ used by metrics/DiagnosticsMetrics.ts
and metrics/MetricsAccumulator.ts
- service/worker/listeners.ts used by graphql/schemaDirectives/
Deprecated.ts
- service/worker/runtime/statusTrack.ts (referenced by lib's
MetricsAccumulator)
- service/worker/runtime/http/middlewares/{settings,requestStats,timings}.ts
used by schemaDirectives/Settings.ts
and by MetricsAccumulator
- service/worker/runtime/http/routes.ts used by clients/apps/
AppGraphQLClient.ts
- service/worker/runtime/graphql/typings.ts schemaDirectives need it
- service/worker/runtime/graphql/utils/translations.ts schemaDirectives need it
- service/worker/runtime/utils/{compose,diff}.ts (compose: used by
service/worker/runtime/
method.ts; diff: used
by service/logger/
metricsLogger.ts)
This list represents the deeper architectural coupling between lib's
'public' code (MetricsAccumulator, DiagnosticsMetrics, Logger,
schemaDirectives, AppGraphQLClient, UserLandTracer) and runtime concerns
(Koa middleware, telemetry exporter wiring, status tracking). Phase 3
deliberately does NOT attempt to break these couplings \u2014 doing so would
require non-trivial refactoring of multiple public classes. Recorded as
'Phase 4+' debt.
TRADE-OFF: SC-003 'zero bytes of Koa/server/middleware in consumer
bundles' is therefore NOT fully met in Phase 3. The PUBLIC SURFACE
(index.ts re-exports) is correctly trimmed (startApp is gone, the
'./service' barrel is gone), but the BYTES of some Koa-touching
middleware files remain in packages/lib because surviving public
classes import them. A future task can refactor the offenders.
packages/lib/src/index.ts changes:
- Dropped 'export * from "./service"' (the barrel that exposed
startApp, appPath, Router). Added a comment explaining the move.
- Retained the 14 transitional internal re-exports added in 1bb14c5
(HttpAgentSingleton, MetricsLogger, statusLabel, cancel,
UserLandTracer, tracing tags/events/fields, cloneAndSanitizeHeaders,
IOMessage, BindingHeader, TenantHeader). Runtime still imports
these via '@vtex/api'.
packages/lib/src/service/globals.d.ts (NEW, 1KB):
- Ambient declaration for 'global.metrics' and 'global.diagnosticsMetrics'.
These were declared in the now-deleted service/index.ts. Lib's
surviving DiagnosticsMetrics / requestStats / timings reference
them; runtime's service/index.ts is what populates them at boot.
packages/runtime/__mocks__/@vtex/diagnostics-semconv.ts (NEW):
- Mirror of lib's existing manual mock; necessary because the 3
relocated tests transitively load @vtex/diagnostics-semconv via
lib's Logger initialization path.
packages/runtime/jest.config.js:
- Added moduleNameMapper for @vtex/diagnostics-semconv (mock),
axios (CJS bundle), and @opentelemetry/otlp-exporter-base subpaths
(forward-port of master e3b6ad5, same as lib's jest config).
packages/runtime/package.json:
- Changed devDependencies '@vtex/api' from '*' to '8.0.0-0'.
Yarn 1 was downloading the latest npm-published 7.x for '*'
instead of symlinking the workspace package; the explicit version
forces the workspace symlink.
- Scoped ci:prettier-check to tests/ (matching lib) with
--no-error-on-unmatched-pattern (tests/ doesn't exist yet in runtime).
Updated public-API tests:
- removed-symbols.test.ts (T017): trimmed list to just 'startApp'.
Documented WHY each formerly-listed symbol no longer applies:
* Router -> the public VTEX InfraClient at clients/infra/Router.ts,
not Koa's router. False alarm.
* HTTP_SERVER_PORT, MAX_WORKERS, UP_SIGNAL, PID, INSPECT_DEBUGGER_PORT
-> still re-exported because lib's index.ts wildcards
'constants' as a whole. Trimming the wildcard to an
explicit allow-list is feasible but out of Phase 3
scope; tracked as known debt.
Verified CI gates:
yarn ci:build OK (both packages compile)
yarn ci:test
lib: 10 suites pass, 1 fails
(snapshot.test.ts: superset
violated because index.d.ts now
LACKS 'export *' lines from
the removed './service' \u2014
EXPECTED red; T030 reset.)
runtime: 3 suites pass, 38 tests pass
(the 3 moved http middleware tests)
Together: 13 suites, 212 pass, 1 fail
yarn lint OK (1 pre-existing warning)
yarn ci:prettier-check OK (scoped to tests/)
Refs: specs/001-split-node-vtex-api-library/tasks.md#T024
added 5 commits
May 18, 2026 11:42
After T024 deleted the carved-out files and dropped './service' from
lib's index.ts, the two contract tests that pinned the public surface
from both directions now sit in their target state:
T018 / preserved-symbols.test.ts:
41/41 assertions GREEN.
Every documented public symbol (Service, IOClients, HttpClient,
error classes, Logger, MetricsAccumulator, GraphQL helpers, tracing
API, cache primitives) is still exported.
T017 / removed-symbols.test.ts:
1/1 assertion GREEN.
startApp is no longer reachable from 'import "@vtex/api"'.
(Other names previously on this list were de-scoped \u2014 see
a6eb0e8 commit body.)
This is an empty marker commit; the actual work was done in 1bb14c5
(add) and a6eb0e8 (subtract). Recording so the task line in tasks.md
points at a concrete SHA.
Refs: specs/001-split-node-vtex-api-library/tasks.md#T025
specs/001-split-node-vtex-api-library/tasks.md#T026
Three things happen here:
1. Regenerate packages/lib/tests/__public_api__/index.d.ts.snapshot
from the post-T024 compiled lib/index.d.ts. The new snapshot:
- SHA-256: f43da6f06c62327174d69873d0a31b3d4eb1ff1ee1ab73572a5be2c09f5a5097
- net delta vs Phase 2 baseline (9fb24765\u2026):
+12 named exports (transitional internal re-exports from T024)
- 1 wildcard 'export * from "./service"' (T024 deletion)
= +11 lines
2. snapshot.test.ts: add a second assertion that checks 'no additions
beyond the snapshot'. Combined with the existing 'no removals'
check, this is now EQUALITY:
- any export in snapshot but not in compiled -> regression error
- any export in compiled but not in snapshot -> expansion error
Both errors include the offending line(s) and tell the reviewer to
either regenerate the snapshot (intentional change) or revert
(unintentional drift).
3. README.md: updated history table; reworded T030 description to
past-tense.
Combined effect: from now on, any change to @vtex/api's public surface
forces a deliberate snapshot update + CHANGELOG entry (T029). The
test runs in lib's ci:test under tests/__public_api__/ and is part of
the contract gate.
Verified:
yarn ci:test -> snapshot.test.ts 3 passed (no removals, no
additions, snapshot non-empty); preserved-symbols
41 passed; removed-symbols 1 passed.
Refs: specs/001-split-node-vtex-api-library/tasks.md#T030
SC-007 (public-API precision gate)
…ream-C carve-out
Author the Keep-a-Changelog entry for @vtex/api@8.0.0-0 documenting:
Removed (1):
- startApp -> service-runtime-node imports it from
@vtex/api-runtime now; consumer apps were never the
intended consumer of this function.
Internal added (14, marked @internal, not public):
HttpAgentSingleton, MetricsLogger, statusLabel, cancel,
UserLandTracer, AppTags, CustomHttpTags, OpentracingTags,
VTEXIncomingRequestTags, RuntimeLogEvents, RuntimeLogFields,
cloneAndSanitizeHeaders, IOMessage, BindingHeader, TenantHeader
Changed:
- Repository is now a Yarn 1 workspaces monorepo
- engines.node stays at >= 8
Known coupling debt (transparent, not blocking 8.0.0):
- SC-003 only partially met (surface trimmed; bytes still in lib)
- Runtime-only constants still reachable via wildcard re-export of
constants.ts. To be resolved in a Phase 4+ task.
The new CHANGELOG.md is a COPY of the repo-root CHANGELOG.md with the
8.0.0-0 stanza inserted between [Unreleased] and [7.3.1]. The root
CHANGELOG.md is unchanged for now \u2014 a future commit can either fold
it back into the lib package or split it per-package.
The 8.0.0-0 entry uses 'user-facing terms' per AGENTS.md's release
discipline: every removed symbol lists a supported alternative
(FR-007), every internal addition is annotated with its runtime
consumer, and known limitations are explicit so adopters of the
'next' dist-tag aren't surprised by what's still bundled.
Refs: specs/001-split-node-vtex-api-library/tasks.md#T029
spec.md FR-007
Tick every Phase 3 task (workstream C \u2014 carve runtime out of @vtex/api)
with its commit SHA(s) and any deviation. Two tasks remain OPEN with
[NEEDS USER] tags because they require access this agent does not have:
T027 \u2014 yarn link @vtex/api against 3 in-org consumer apps and
verify they still build/test green. Requires consumer-app
repos.
T028 \u2014 measure SC-003 byte count for koa/server/middleware in the
consumer app's compiled bundle.
Deviations recorded per task:
T017 \u2014 list narrowed during T024 from 7 to 1 entry; rationale
documented inline (false positives for Router as InfraClient;
shared-constants debt for HTTP_SERVER_PORT et al.).
T019\u2013T022 \u2014 collapsed into one ADD commit (1bb14c5) and one
SUBTRACT commit (a6eb0e8) per option-2 strategy chosen by
user. Lib KEEPS some carved files (telemetry, tracing, metrics,
listeners, statusTrack, settings/requestStats/timings,
routes, graphql/typings, graphql/utils/translations) because
surviving public classes import them \u2014 documented as known
coupling debt to address in Phase 4+.
T022 \u2014 lib's tracing/metrics singletons (NFR-O11y-005 ownership
split) preserved correctly; surviving telemetry files KEPT
in lib due to coupling above.
T023 \u2014 'Runtime MUST NOT have a value-level import from lib' (FR-004)
partially achieved: 71 imports converted to type-only; 54
value imports remain (HeaderKeys, LogLevel, IOClients ctor,
error classes, MetricsAccumulator). Full elimination requires
copying constants/errors into runtime \u2014 deferred.\n T024 \u2014 'allow-list' (constitution principle I) partially applied:
dropped 'export * from "./service"' but kept the other 14
wildcards (their target subtrees are legitimately public).
Added 12 transitional internal named re-exports for runtime\n cross-package access.
T029 \u2014 CHANGELOG split: new packages/lib/CHANGELOG.md created from
the root CHANGELOG.md + the [8.0.0-0] stanza. Root CHANGELOG.md
unchanged for now.
Phase 3 checkpoint flipped to '\u26a0\ufe0f DONE WITH KNOWN DEBT' with the two
[NEEDS USER] tasks explicitly noted. US1 is independently shippable
contingent on those validations.
Refs: specs/001-split-node-vtex-api-library/tasks.md (Phase 3 section)
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.
What is the purpose of this pull request?
What problem is this solving?
How should this be manually tested?
Screenshots or example usage
Types of changes