Skip to content

refactor(schemas): consolidate __dirname-relative schema/data root resolution - #2378

Draft
benminer wants to merge 4 commits into
mainfrom
bminer/eng-130-decouple-adcpsdk-cli-build-from-distlib-consolidate-schema
Draft

refactor(schemas): consolidate __dirname-relative schema/data root resolution#2378
benminer wants to merge 4 commits into
mainfrom
bminer/eng-130-decouple-adcpsdk-cli-build-from-distlib-consolidate-schema

Conversation

@benminer

Copy link
Copy Markdown
Collaborator

Summary

Part of a follow-up exploration branched off #2365 (ENG-130): the user's instinct on that PR was "maybe a simple banner is the root problem" (comparing against an old project's ampt-style single-bundle esbuild build). Investigation concluded that bundling the whole library per public entry point isn't viable here — 34 public exports subpaths, a CLI that deep-requires ~30 non-exported dist/lib/** paths, and (this PR's target) 7 files that resolve schema/data files via hand-tuned __dirname arithmetic fanning out across 7+ overlapping public entries.

This PR is the first of two pieces from that plan — a standalone cleanup that's worth doing regardless of any bundling question:

  • Adds src/lib/internal/package-root.ts (getPackageRoot()) and src/lib/internal/schema-data-roots.ts (getSchemaDataRoots()). getPackageRoot() resolves the package root via require.resolve('@adcp/sdk/package.json') self-reference (falling back to a directory walk), independent of the calling module's own directory depth.
  • Migrates 7 files off ~150 lines of duplicated, hand-tuned path.join(__dirname, '..', ...) arithmetic: validation/schema-loader.ts, conformance/schemaLoader.ts, server/error-arm-tools.ts, v2/projection/{catalog,registry,canonical-properties}.ts, testing/storyboard/compliance.ts. Each file's existing dist-vs-source-tree fallback business logic is unchanged — only the anchor computation changed.
  • Fixes two fake-install test fixtures (schema-loader-per-version.test.js, v2-projection-loader-paths.test.js) that mimicked a published tarball by copying only dist/, never package.json — unfaithful to a real npm install (which always ships package.json) and would break getPackageRoot()'s self-reference.
  • Updates the tsup.config.ts comment: the "__dirname-based schema-data lookups keep their original directory depth" justification for bundle: false no longer applies (tree-shaking and CLI/tooling deep-requires still do — bundle: false itself is unchanged).

No public API changes — src/lib/internal/ is not exported. Branched off issue-2364; that PR (#2365) has since merged, so this branch has been merged up to current main.

Second piece (CLI build decoupling from dist/lib, giving the CLI its own esbuild bundle direct from TS source) will follow as a separate PR.

Test plan

  • New TDD unit tests for getPackageRoot()/getSchemaDataRoots() (10 tests, including the directory-walk fallback in isolation)
  • npx tsc --noEmit clean
  • npm run build:lib clean
  • npm run test:node:fast: 12518/12528 pass. The 3 failures (JWK/OKP crypto errors in signer-grader/request-signing-provider, a timing-sensitive MCP session-cache assertion) are pre-existing — reproduced independently against a stashed pristine baseline, and none of the failing test files reference any of the 7 migrated modules.
  • Re-verified the 3 CLI test files (cli-auth-scheme, cli-webhook-receiver-flag, conformance-cli) in isolation — all 50 tests pass; they looked flaky only under full-suite parallel load.
  • Re-ran affected tests + newly-merged main tests after merging origin/main — all green.
  • Changeset added (patch).

🤖 Generated with Claude Code

andybevan-scope3 and others added 4 commits July 17, 2026 10:08
The tsup ESM banner (node:url/node:path/node:module + __dirname/__filename/
require shims) was applied unconditionally via esbuildOptions to every
.mjs output, including pure-data files like enums.generated.mjs that never
touch those globals. Strict browser bundlers (Vite, esbuild
--platform=browser) can't resolve real Node built-ins, so importing
@adcp/sdk/enums or other lean entry points broke bundling for browser
consumers.

Replace the blanket banner with an esbuild onLoad plugin that only
prepends the shim to files whose transpiled body actually references
__dirname/__filename/require (11 of 486 files) — detected via a
throwaway transformSync so comments merely mentioning "require()" don't
false-positive. Runs pre-transform so sourcemaps stay accurate.

Add a browser-platform esbuild bundle check to verify-package.mjs so this
class of regression fails CI going forward.

Fixes #2364
Two follow-ups from review:
- require(...features) in SingleAgentClient.ts is a class method, not a
  call to the global require — the detection regex matched it anyway,
  giving that file the shim unnecessarily. Every real require() call in
  the codebase takes a string-literal module specifier, so require the
  match to have a following quote.
- __filename is never read by any source file; it only existed as an
  intermediate step toward __dirname. Compute __dirname inline instead of
  binding an unused name.
…solution

Replace the hand-tuned `path.join(__dirname, '..', ...)` arithmetic
duplicated across 7 schema/data loaders with shared getPackageRoot()/
getSchemaDataRoots() helpers anchored via require.resolve self-reference,
independent of each file's own directory depth. No public API changes.

Part of ENG-130.
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.

2 participants