Files
hyperframes/packages/core/package-subpaths.json
Vance IngallsandClaude Opus 5 71ee156dac feat(studio): browser canary binding + leaf subpath imports
Adds the Studio (browser) binding so a canary can span the CLI and the editor,
and fixes a bundling mistake the studio test suite caught.

## The binding

Same public API as the CLI — `isCanaryEnabled("name")` — so a call site reads
identically whether it runs in Node or the browser. Three inputs differ:

- UNIT ID: `resolveStudioDistinctId()`, which already adopts
  `window.__HF_CLI_DISTINCT_ID` when the CLI launched Studio. A CLI-launched
  Studio therefore lands in the SAME cohort as the CLI: a rollout spanning
  render and editor is coherent for that user instead of enrolling their
  terminal but not their editor. A test pins that the id is passed through
  unmodified — prefixing or re-hashing it would silently break that parity.

- OVERRIDE: no `process.env` in a page, so `?hf_canary_<name>=on` mirrored
  into sessionStorage. Session scope is deliberate. A URL is the right carrier
  (shareable — "support: open this link"), but persisting a URL-borne override
  to localStorage would let one click silently pin a browser into a cohort
  forever, long after anyone remembers why. Closing the tab is the reset;
  `=reset` clears it explicitly.

- EXCLUSION: `navigator.webdriver` stands in for the CLI's `is_ci`. Automated
  browsers mint a fresh localStorage id per run, so they would hop cohorts
  between runs — noise in the signal, nothing learned about real users. An
  override still reaches them, which is how you test a canary under Playwright.

Studio's `trackEvent` now attaches `canaries` to every event, mirroring the CLI.

## The bundling fix

Importing the `@hyperframes/core` barrel into studio browser code broke two
unrelated hook test files with an esbuild TextEncoder invariant violation. The
barrel re-exports the whole core surface (parsers, lint, studio-server), so it
drags a Node-oriented dependency graph into a browser bundle — the test
failure was the symptom, the bundle bloat was the bug.

`@hyperframes/core` now exposes `./canary` and `./canary-registry`, declared in
packages/core/package-subpaths.json (the generated source of truth for exports —
hand-editing package.json is reverted by the sync script) and marked
`environments: [browser, bun, node]`. Both the studio AND cli bindings import
the leaf modules; the CLI gets the same benefit for a different reason, since
this resolves on the startup path — the reason the producer is lazily loaded.

Verified: the two hook files pass again; 269 studio files / 2982 tests, 98
core / 1433, 166 cli / 2194 green, `bun run lint` clean including the subpath
check. Fault-injection confirms both design decisions are pinned — swapping
session for local storage fails the scope test, prefixing the unit id fails the
CLI/Studio cohort-parity test.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 15:14:35 -07:00

307 lines
11 KiB
JSON

{
"package": "@hyperframes/core",
"localNodeRuntime": true,
"subpaths": {
".": {
"source": "./src/index.ts",
"runtime": "./dist/index.js",
"types": "./dist/index.d.ts",
"environments": ["bun", "node"]
},
"./package.json": {
"source": "./package.json",
"runtime": "./package.json",
"types": null,
"environments": ["browser", "bun", "node"]
},
"./canary": {
"source": "./src/canary.ts",
"runtime": "./dist/canary.js",
"types": "./dist/canary.d.ts",
"environments": ["browser", "bun", "node"]
},
"./canary-registry": {
"source": "./src/canaryRegistry.ts",
"runtime": "./dist/canaryRegistry.js",
"types": "./dist/canaryRegistry.d.ts",
"environments": ["browser", "bun", "node"]
},
"./beats": {
"source": "./src/beats/index.ts",
"runtime": "./dist/beats/index.js",
"types": "./dist/beats/index.d.ts",
"environments": ["browser", "bun", "node"]
},
"./html-attr-safety": {
"source": "./src/utils/htmlAttrSafety.ts",
"runtime": "./dist/utils/htmlAttrSafety.js",
"types": "./dist/utils/htmlAttrSafety.d.ts",
"environments": ["browser", "bun", "node"]
},
"./composition-contract": {
"source": "./src/compositionContract.ts",
"runtime": "./dist/compositionContract.js",
"types": "./dist/compositionContract.d.ts",
"environments": ["browser", "bun", "node"]
},
"./editing": {
"source": "./src/editing/affordances.ts",
"runtime": "./dist/editing/affordances.js",
"types": "./dist/editing/affordances.d.ts",
"environments": ["browser", "bun", "node"]
},
"./editing/draft-markers": {
"source": "./src/editing/draftMarkers.ts",
"runtime": "./dist/editing/draftMarkers.js",
"types": "./dist/editing/draftMarkers.d.ts",
"environments": ["browser", "bun", "node"]
},
"./variables": {
"source": "./src/variables.ts",
"runtime": "./dist/variables.js",
"types": "./dist/variables.d.ts",
"environments": ["browser", "bun", "node"]
},
"./slideshow": {
"source": "./src/slideshow/index.ts",
"runtime": "./dist/slideshow/index.js",
"types": "./dist/slideshow/index.d.ts",
"environments": ["browser", "bun", "node"]
},
"./generators": {
"source": "./src/generators/hyperframes.ts",
"runtime": "./dist/generators/hyperframes.js",
"types": "./dist/generators/hyperframes.d.ts",
"environments": ["browser", "bun", "node"]
},
"./lint": {
"source": "./src/lint/index.ts",
"runtime": "./dist/lint/index.js",
"types": "./dist/lint/index.d.ts",
"environments": ["bun", "node"]
},
"./compiler": {
"source": "./src/compiler/index.ts",
"runtime": "./dist/compiler/index.js",
"types": "./dist/compiler/index.d.ts",
"environments": ["bun", "node"]
},
"./color-grading": {
"source": "./src/colorGrading.ts",
"runtime": "./dist/colorGrading.js",
"types": "./dist/colorGrading.d.ts",
"environments": ["browser", "bun", "node"]
},
"./color-luts": {
"source": "./src/colorLuts.ts",
"runtime": "./dist/colorLuts.js",
"types": "./dist/colorLuts.d.ts",
"environments": ["browser", "bun", "node"]
},
"./media-grade-analyzer": {
"source": "./src/mediaGradeAnalyzer.ts",
"runtime": "./dist/mediaGradeAnalyzer.js",
"types": "./dist/mediaGradeAnalyzer.d.ts",
"environments": ["bun", "node"]
},
"./storyboard": {
"source": "./src/storyboard/index.ts",
"runtime": "./dist/storyboard/index.js",
"types": "./dist/storyboard/index.d.ts",
"environments": ["browser", "bun", "node"]
},
"./runtime": {
"source": "./dist/hyperframe.runtime.iife.js",
"runtime": "./dist/hyperframe.runtime.iife.js",
"types": null,
"environments": ["browser"]
},
"./runtime/clipTree": {
"source": "./src/runtime/clipTree.ts",
"runtime": "./dist/runtime/clipTree.js",
"types": "./dist/runtime/clipTree.d.ts",
"environments": ["browser", "bun", "node"]
},
"./runtime/custom-ease": {
"source": "./src/runtime/customEase.ts",
"runtime": "./dist/runtime/customEase.js",
"types": "./dist/runtime/customEase.d.ts",
"environments": ["browser", "bun", "node"]
},
"./runtime/start-expression": {
"source": "./src/runtime/startExpression.ts",
"runtime": "./dist/runtime/startExpression.js",
"types": "./dist/runtime/startExpression.d.ts",
"environments": ["browser", "bun", "node"]
},
"./runtime/start-resolver": {
"source": "./src/runtime/startResolver.ts",
"runtime": "./dist/runtime/startResolver.js",
"types": "./dist/runtime/startResolver.d.ts",
"environments": ["browser", "bun", "node"]
},
"./runtime/protocol": {
"source": "./src/runtime/protocol.ts",
"runtime": "./dist/runtime/protocol.js",
"types": "./dist/runtime/protocol.d.ts",
"environments": ["browser", "bun", "node"]
},
"./runtime/stacking-context": {
"source": "./src/runtime/stackingContext.ts",
"runtime": "./dist/runtime/stackingContext.js",
"types": "./dist/runtime/stackingContext.d.ts",
"environments": ["browser", "bun", "node"]
},
"./compiler/html-document": {
"source": "./src/compiler/htmlDocument.ts",
"runtime": "./dist/compiler/htmlDocument.js",
"types": "./dist/compiler/htmlDocument.d.ts",
"environments": ["browser", "bun", "node"]
},
"./runtime/position-edits": {
"source": "./src/runtime/positionEdits.ts",
"runtime": "./dist/runtime/positionEdits.js",
"types": "./dist/runtime/positionEdits.d.ts",
"environments": ["browser", "bun", "node"]
},
"./runtime/position-edits-render": {
"source": "./src/generated/position-edits-render-inline.ts",
"runtime": "./dist/generated/position-edits-render-inline.js",
"types": "./dist/generated/position-edits-render-inline.d.ts",
"environments": ["browser", "bun", "node"]
},
"./runtime/lottie-readiness": {
"source": "./src/lottieReadiness.ts",
"runtime": "./dist/lottieReadiness.js",
"types": "./dist/lottieReadiness.d.ts",
"environments": ["browser", "bun", "node"]
},
"./studio-api": {
"source": "./src/studio-api/index.ts",
"runtime": "./dist/studio-api/index.js",
"types": "./dist/studio-api/index.d.ts",
"environments": ["bun", "node"]
},
"./studio-api/screenshot-clip": {
"source": "./src/studio-api/helpers/screenshotClip.ts",
"runtime": "./dist/studio-api/helpers/screenshotClip.js",
"types": "./dist/studio-api/helpers/screenshotClip.d.ts",
"environments": ["bun", "node"]
},
"./studio-api/manual-edits-render-script": {
"source": "./src/studio-api/helpers/manualEditsRenderScript.ts",
"runtime": "./dist/studio-api/helpers/manualEditsRenderScript.js",
"types": "./dist/studio-api/helpers/manualEditsRenderScript.d.ts",
"environments": ["bun", "node"]
},
"./studio-api/studio-motion-render-script": {
"source": "./src/studio-api/helpers/studioMotionRenderScript.ts",
"runtime": "./dist/studio-api/helpers/studioMotionRenderScript.js",
"types": "./dist/studio-api/helpers/studioMotionRenderScript.d.ts",
"environments": ["bun", "node"]
},
"./studio-api/draft-markers": {
"source": "./src/studio-api/helpers/draftMarkers.ts",
"runtime": "./dist/studio-api/helpers/draftMarkers.js",
"types": "./dist/studio-api/helpers/draftMarkers.d.ts",
"environments": ["browser", "bun", "node"]
},
"./studio-api/finite-mutation": {
"source": "./src/studio-api/helpers/finiteMutation.ts",
"runtime": "./dist/studio-api/helpers/finiteMutation.js",
"types": "./dist/studio-api/helpers/finiteMutation.d.ts",
"environments": ["bun", "node"]
},
"./text": {
"source": "./src/text/index.ts",
"runtime": "./dist/text/index.js",
"types": "./dist/text/index.d.ts",
"environments": ["browser", "bun", "node"]
},
"./registry": {
"source": "./src/registry/index.ts",
"runtime": "./dist/registry/index.js",
"types": "./dist/registry/index.d.ts",
"environments": ["browser", "bun", "node"]
},
"./media-volume-envelope": {
"source": "./src/runtime/mediaVolumeEnvelope.ts",
"runtime": "./dist/runtime/mediaVolumeEnvelope.js",
"types": "./dist/runtime/mediaVolumeEnvelope.d.ts",
"environments": ["browser", "bun", "node"]
},
"./hf-ids": {
"source": "./src/parsers/hfIds.ts",
"runtime": "./dist/parsers/hfIds.js",
"types": "./dist/parsers/hfIds.d.ts",
"environments": ["browser", "bun", "node"]
},
"./gsap-parser": {
"source": "./src/parsers/gsapParserExports.ts",
"runtime": "./dist/parsers/gsapParserExports.js",
"types": "./dist/parsers/gsapParserExports.d.ts",
"environments": ["browser", "bun", "node"]
},
"./gsap-parser-acorn": {
"source": "./src/parsers/gsapParserAcorn.ts",
"runtime": "./dist/parsers/gsapParserAcorn.js",
"types": "./dist/parsers/gsapParserAcorn.d.ts",
"environments": ["browser", "bun", "node"]
},
"./gsap-writer-acorn": {
"source": "./src/parsers/gsapWriterAcorn.ts",
"runtime": "./dist/parsers/gsapWriterAcorn.js",
"types": "./dist/parsers/gsapWriterAcorn.d.ts",
"environments": ["browser", "bun", "node"]
},
"./gsap-constants": {
"source": "./src/parsers/gsapConstants.ts",
"runtime": "./dist/parsers/gsapConstants.js",
"types": "./dist/parsers/gsapConstants.d.ts",
"environments": ["browser", "bun", "node"]
},
"./spring-ease": {
"source": "./src/parsers/springEase.ts",
"runtime": "./dist/parsers/springEase.js",
"types": "./dist/parsers/springEase.d.ts",
"environments": ["browser", "bun", "node"]
},
"./wiggle-ease": {
"source": "./src/runtime/wiggleEase.ts",
"runtime": "./dist/runtime/wiggleEase.js",
"types": "./dist/runtime/wiggleEase.d.ts",
"environments": ["browser", "bun", "node"]
},
"./fonts/aliases": {
"source": "./src/fonts/aliases.ts",
"runtime": "./dist/fonts/aliases.js",
"types": "./dist/fonts/aliases.d.ts",
"environments": ["browser", "bun", "node"]
},
"./fonts/system-locator": {
"source": "./src/fonts/systemFontLocator.ts",
"runtime": "./dist/fonts/systemFontLocator.js",
"types": "./dist/fonts/systemFontLocator.d.ts",
"environments": ["bun", "node"]
},
"./figma": {
"source": "./src/figma/index.ts",
"runtime": "./dist/figma/index.js",
"types": "./dist/figma/index.d.ts",
"environments": ["bun", "node"]
},
"./schemas/registry.json": {
"source": "./schemas/registry.json",
"runtime": "./schemas/registry.json",
"types": null,
"environments": ["browser", "bun", "node"]
},
"./schemas/registry-item.json": {
"source": "./schemas/registry-item.json",
"runtime": "./schemas/registry-item.json",
"types": null,
"environments": ["browser", "bun", "node"]
}
}
}