Skip to content

fix: emit relative imports in dist (drop self-referential @/ alias)#16

Merged
Isonimus merged 2 commits into
mainfrom
fix/dist-self-import-paths
Jun 10, 2026
Merged

fix: emit relative imports in dist (drop self-referential @/ alias)#16
Isonimus merged 2 commits into
mainfrom
fix/dist-self-import-paths

Conversation

@Isonimus

@Isonimus Isonimus commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

The bug

@tindalabs/shield's published dist/otel.js imported its internal path alias:

import { ContentProtector } from '@/core/index.js';

tsc does not rewrite paths aliases (@/* → src/*) to relative paths on emit, so the alias leaked into the shipped package. Any consumer bundling shield without replicating that alias — Webpack/Next, Vite, esbuild, etc. — fails on import of attachShieldToSpan:

Module not found: Can't resolve '@/core/index.js'

This breaks the OTel entry point for the common bundler case. (assess() / ContentProtector happen not to traverse otel.ts, which is why it wasn't caught earlier.)

The fix

src/otel.ts was the only file using the alias. It now imports relatively:

import { ContentProtector } from './core/index.js';
import type { ContentProtectionOptions, CustomEventHandlers } from './types/index.js';

So dist/ is alias-free with no new build tooling.

Verification

  • Clean tsc build; grep "from '@/'" dist → nothing.
  • dist/otel.js now imports ./core/index.js.
  • Full suite green: 371 passed, 1 skipped (372).

Surfaced while wiring shield into the tindalabs.dev static build (Next/Webpack), where it was a hard build failure. CHANGELOG updated — this is a consumer-visible fix, so it warrants a 0.1.1 patch.

Optional hardening (not in this PR): add tsc-alias to the build, or a lint rule banning @/ in src/, to prevent recurrence if the alias is reintroduced.

Isonimus added 2 commits June 9, 2026 10:42
assess() detection was jsdom-verified only — and jsdom has no Worker, so
the DevTools debugger detector and real-engine timing/navigator behaviour
were never exercised. A browser update could silently turn a detector into
a false negative without CI noticing.

Add an e2e/ Playwright package: a Vite-built fixture loads Shield's source
and exposes assess() on window; the spec drives it via page.evaluate and
asserts result shape, that the shield.automation.webdriver signal mirrors
the live navigator.webdriver, that a forced extension signature composes
risk -> flags -> spanAttributes end-to-end, and that a clean session stays
lean. This exercises the Worker-based DevTools debugger detector jsdom
cannot run.

CI runs Chromium + Firefox on ubuntu and WebKit on macos-latest (Playwright
WebKit throws an internal error on Linux regardless of the static server, so
it is gated off Linux and verified natively on macOS — the engine where
timing heuristics diverge most). 8/8 green on Chromium + Firefox locally.
dist/otel.js imported '@/core/index.js' and '@/types/index.js' — shield's
internal TypeScript path alias, which tsc does not rewrite to a relative path
on emit. Any consumer bundling shield without replicating the alias (Webpack/
Next, Vite, …) failed with 'Module not found: Can't resolve @/core/index.js',
breaking attachShieldToSpan on import.

src/otel.ts was the only file using the alias; it now imports relatively, so
dist/ is alias-free. Verified: clean build, no '@/' left in dist, 372 tests
green. Surfaced while wiring shield into the tindalabs.dev static build.
Comment thread e2e/serve.mjs Dismissed
@Isonimus Isonimus merged commit 4edad9f into main Jun 10, 2026
5 of 6 checks passed
@Isonimus Isonimus deleted the fix/dist-self-import-paths branch June 10, 2026 10:56
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