Skip to content

Conversation

@jdreetz
Copy link
Collaborator

@jdreetz jdreetz commented Feb 12, 2026

Split UI components into dedicated packages

Extracts watch, publish, and shared UI code out of @moq/hang into their own packages, establishing clearer boundaries between media logic and UI.

Changes

  • @moq/ui-core (new) — Shared UI primitives (Button, Icon, Stats panel) used by both watch and publish UIs. Uses structural interfaces for stats provider types to avoid depending on @moq/watch or @moq/hang.
  • @moq/watch (new) — Watch/subscribe logic + optional @moq/watch/ui overlay (<hang-watch-ui>), built with Vite + SolidJS.
  • @moq/publish (new) — Publish logic + optional @moq/publish/ui overlay (<hang-publish-ui>), built with Vite + SolidJS.
  • @moq/hang — Removed all watch/publish/UI code. Now contains only the core media layer: catalog, container (CMAF + Legacy), and utilities.

Build

Each package has two TypeScript configs:

  • tsconfig.json — IDE + type-checking (includes UI)
  • tsconfig.build.json — Declaration emit only (excludes UI, which Vite handles)

Documentation

  • Updated doc/js/ pages and package READMEs to reflect the new structure
  • Corrected UI web component examples to show the wrapping pattern
  • Fixed license file paths

Nix

  • Added git and cmake to flake.nix rustDeps — required by boring-sys to build BoringSSL

Extract shared UI components (Button, Icon, Stats) and CSS (variables,
flex, button styles, stats styles) from @moq/hang-ui into a new
@moq/ui-core package. This is the first milestone in restructuring
the codebase to separate watch/publish from @moq/hang.

Files changed:

- js/ui-core/ (new): New @moq/ui-core package with vite lib build,
  containing all shared UI components, icons (20 SVGs), stats panel
  with providers, and CSS theme variables.

- js/hang-ui/src/shared/ (deleted): Moved entirely into @moq/ui-core.

- js/hang-ui/src/watch/element.tsx: Stats import now from @moq/ui-core.

- js/hang-ui/src/watch/components/{PlayPauseButton,FullscreenButton,
  VolumeSlider,StatsButton}.tsx: Button and Icon imports now from
  @moq/ui-core instead of relative ../../shared/ paths.

- js/hang-ui/src/publish/components/{CameraSourceButton,FileSourceButton,
  ScreenSourceButton,MediaSourceSelector,NothingSourceButton,
  MicrophoneSourceButton}.tsx: Same import update as watch components.

- js/hang-ui/src/watch/styles/index.css: CSS @imports updated from
  relative ../../shared/ paths to @moq/ui-core package paths.

- js/hang-ui/src/publish/styles/index.css: Same CSS @import update.

- js/hang-ui/package.json: Added @moq/ui-core as peer dependency.

- js/hang-ui/vite.config.ts: Added @moq/ui-core to rollup externals
  so it is not bundled into the hang-ui build output.

- js/hang-ui/README.md: Updated project structure and module overview
  to reflect that shared/ has moved to @moq/ui-core.

- package.json (root): Added js/ui-core to workspaces array.

- CLAUDE.md: Added ui-core/ to the JS project structure listing.

- README.md (root): Added @moq/ui-core row to the TypeScript packages
  table.

- js/docs/restructure-plan.md (new): Full restructuring plan with
  8 milestones covering the migration from the current @moq/hang
  monolith to separate @moq/watch, @moq/publish, and @moq/ui-core
  packages.
Move the watch/subscribe module from @moq/hang into a standalone
@moq/watch package. This separates watch functionality so it can be
consumed independently, and exposes container and util modules from
@moq/hang for shared use.

Files changed:

- js/watch/ (new): New @moq/watch package with tsc build, containing
  all 30 watch source files (broadcast, preview, sync, mse, user,
  audio/*, video/*, chat/*, location/*), plus worklet.d.ts for vite
  worker imports, and README documenting the Web Component and JS API.

- js/hang/src/watch/ (deleted): Moved entirely into @moq/watch.

- js/hang/package.json: Removed ./watch and ./watch/element exports;
  added ./container, ./util/hex, and ./util/libav exports so @moq/watch
  can import shared modules. Removed watch from sideEffects array.

- js/hang/src/index.ts: Removed 'export * as Watch' barrel re-export
  since watch is now its own package.

- js/hang/README.md: Updated import examples and JS API code samples
  to reference @moq/watch/element and @moq/watch instead of
  @moq/hang/watch. Added note pointing to @moq/watch README.

- js/watch/src/{broadcast,preview,user}.ts: Updated catalog imports
  from relative ../catalog to @moq/hang/catalog.

- js/watch/src/{chat,location}/*.ts: Updated catalog imports from
  relative ../../catalog to @moq/hang/catalog.

- js/watch/src/audio/{decoder,mse}.ts: Updated catalog, container,
  and util imports from relative ../../* to @moq/hang/*.

- js/watch/src/video/{decoder,mse,source}.ts: Same import updates
  as audio files.

- js/watch/src/audio/source.ts: Updated catalog import to
  @moq/hang/catalog.

- js/ui-core/src/stats/types.ts: Changed Hang.Watch.* type references
  to use new 'import * as Watch from @moq/watch' since Watch was
  removed from @moq/hang barrel.

- js/ui-core/package.json: Added @moq/watch as peer dependency for
  the stats types.

- js/hang-ui/src/watch/{context,element,index}.tsx: Updated imports
  from @moq/hang/watch/element to @moq/watch/element.

- js/hang-ui/src/watch/components/BufferControl.tsx: Updated
  BufferedRange import from @moq/hang/watch to @moq/watch.

- js/hang-ui/package.json: Added @moq/watch as peer dependency.

- js/hang-ui/vite.config.ts: Added @moq/watch to rollup externals.

- js/hang-demo/src/index.ts: Updated HangWatch import from
  @moq/hang/watch/element to @moq/watch/element.

- js/hang-demo/package.json: Added @moq/watch as dependency.

- package.json (root): Added js/watch to workspaces array.

- CLAUDE.md: Added watch/ to the JS project structure listing.

- README.md (root): Added @moq/watch row to the TypeScript packages
  table.
Move the publish module from @moq/hang into a standalone @moq/publish
package. This separates publish functionality so it can be consumed
independently, mirroring the @moq/watch extraction in Milestone 2.

Files changed:

- js/publish/ (new): New @moq/publish package with tsc build, containing
  all 26 publish source files (broadcast, preview, user, audio/*,
  video/*, chat/*, location/*, source/*), plus worklet.d.ts for vite
  worker imports, and README documenting the Web Component and JS API.

- js/hang/src/publish/ (deleted): Moved entirely into @moq/publish.

- js/hang/package.json: Removed ./publish and ./publish/element exports;
  added ./util/hacks export so @moq/publish can import isFirefox.
  Removed publish from sideEffects array.

- js/hang/src/index.ts: Removed 'export * as Publish' barrel re-export
  since publish is now its own package.

- js/hang/README.md: Updated import examples and JS API code samples
  to reference @moq/publish/element and @moq/publish instead of
  @moq/hang/publish. Added notes pointing to @moq/publish README.

- js/publish/src/{broadcast,preview,user}.ts: Updated catalog imports
  from relative ../catalog to @moq/hang/catalog.

- js/publish/src/{chat,location}/*.ts: Updated catalog imports from
  relative ../../catalog to @moq/hang/catalog.

- js/publish/src/audio/encoder.ts: Updated catalog, container, and
  libav imports from relative ../../* to @moq/hang/*.

- js/publish/src/video/encoder.ts: Updated catalog, container, and
  hacks imports from relative ../../* to @moq/hang/*.

- js/publish/src/video/index.ts: Updated catalog import to
  @moq/hang/catalog.

- js/publish/src/location/index.ts: Changed barrel import
  'import { Catalog } from "../.."' to 'import * as Catalog from
  @moq/hang/catalog'.

- js/publish/src/index.ts: Updated comment to reference
  @moq/publish/element instead of @moq/hang/publish/element.

- js/hang-ui/src/publish/{context,element,index}.tsx: Updated imports
  from @moq/hang/publish/element to @moq/publish/element.

- js/hang-ui/package.json: Added @moq/publish as peer dependency.

- js/hang-ui/vite.config.ts: Added @moq/publish to rollup externals.

- js/hang-demo/src/publish.ts: Updated HangPublish import from
  @moq/hang/publish/element to @moq/publish/element.

- js/hang-demo/package.json: Added @moq/publish as dependency.

- package.json (root): Added js/publish to workspaces array.

- CLAUDE.md: Added publish/ to the JS project structure listing.

- README.md (root): Added @moq/publish row to the TypeScript packages
  table.
Move the watch UI web component from @moq/hang-ui into @moq/watch,
co-locating the UI with the logic it wraps. The <hang-watch-ui>
custom element is now available via @moq/watch/ui.

Files changed:

- js/watch/src/ui/ (new): 15 files moved from hang-ui/src/watch/ —
  context.tsx, element.tsx, index.tsx, hooks/use-watch-ui.ts,
  styles/index.css, and 10 components (BufferControl, BufferingIndicator,
  FullscreenButton, LatencySlider, PlayPauseButton, QualitySelector,
  StatsButton, VolumeSlider, WatchControls, WatchStatusIndicator).

- js/watch/src/ui/{context,element,index}.tsx: Updated imports from
  @moq/watch/element to ../element and @moq/watch to .. (now local
  within the package).

- js/watch/src/ui/components/BufferControl.tsx: Updated BufferedRange
  import from @moq/watch to ../.. (local).

- js/watch/package.json: Added ./ui export pointing to src/ui/index.tsx;
  added src/ui/index.tsx to sideEffects; added @moq/ui-core dependency;
  added solid-element, solid-js, vite, vite-plugin-solid as dev deps;
  updated build script to run both tsc and vite.

- js/watch/vite.config.ts (new): Vite lib mode config building the UI
  entry point with solid plugin, externalizing @moq/hang, @moq/lite,
  @moq/signals, @moq/ui-core. Uses emptyOutDir: false to preserve
  tsc output in dist/.

- js/watch/tsconfig.json: Added exclude for src/ui since .tsx files
  are built by vite, not tsc.

- js/watch/README.md: Added UI Web Component section documenting
  <hang-watch-ui> element and its dependency on @moq/ui-core.

- js/hang-ui/src/watch/ (deleted): Moved entirely into @moq/watch/ui.

- js/hang-ui/package.json: Removed ./watch export and sideEffect;
  removed @moq/watch peer dependency.

- js/hang-ui/vite.config.ts: Removed watch entry point and @moq/watch
  from rollup externals.

- js/hang-demo/src/index.ts: Updated watch UI import from
  @moq/hang-ui/watch to @moq/watch/ui.
Move the publish UI web component from @moq/hang-ui into @moq/publish,
co-locating the UI with the logic it wraps. The <hang-publish-ui>
custom element is now available via @moq/publish/ui.

Files changed:

- js/publish/src/ui/ (new): 17 files moved from hang-ui/src/publish/ —
  context.tsx, element.tsx, index.tsx, hooks/use-publish-ui.ts,
  styles/{index,controls,media-selector,source-button,status-indicator}.css,
  and 8 components (CameraSourceButton, FileSourceButton,
  MediaSourceSelector, MicrophoneSourceButton, NothingSourceButton,
  PublishControls, PublishStatusIndicator, ScreenSourceButton).

- js/publish/src/ui/{context,element,index}.tsx: Updated imports from
  @moq/publish/element to ../element (now local within the package).

- js/publish/package.json: Added ./ui export pointing to src/ui/index.tsx;
  added src/ui/index.tsx to sideEffects; added @moq/ui-core dependency;
  added solid-element, solid-js, vite, vite-plugin-solid as dev deps;
  updated build script to run both tsc and vite.

- js/publish/vite.config.ts (new): Vite lib mode config building the UI
  entry point with solid plugin, externalizing @moq/hang, @moq/lite,
  @moq/signals, @moq/ui-core. Uses emptyOutDir: false to preserve
  tsc output in dist/.

- js/publish/tsconfig.json: Added exclude for src/ui since .tsx files
  are built by vite, not tsc.

- js/publish/README.md: Added UI Web Component section documenting
  <hang-publish-ui> element and its dependency on @moq/ui-core.

- js/hang-ui/src/publish/ (deleted): Moved entirely into @moq/publish/ui.

- js/hang-ui/package.json: Removed ./publish export, sideEffect, and
  all peer dependencies (package is now empty).

- js/hang-ui/vite.config.ts: Removed publish entry point (entry is now
  empty object).

- js/hang-demo/src/publish.ts: Updated publish UI import from
  @moq/hang-ui/publish to @moq/publish/ui.
Milestone 6 — Remove @moq/hang-ui:
- Delete js/hang-ui/ package entirely
- Remove @moq/hang-ui dep from hang-demo/package.json
- Remove js/hang-ui from root package.json workspaces
- Delete doc/js/@moq/hang-ui.md
- Update sidebar: replace @moq/hang-ui with @moq/watch, @moq/publish, @moq/ui-core
- Update doc/index.md, doc/js/index.md, doc/js/env/web.md references
- Update doc/js/@moq/hang/watch.md and publish.md SolidJS sections
- Update doc/js/@moq/signals.md import reference
- Update all @moq/hang/watch/element → @moq/watch/element imports in docs
- Update all @moq/hang/publish/element → @moq/publish/element imports in docs
- Update CLAUDE.md: remove hang-ui from structure, update tooling
- Update README.md: remove @moq/hang-ui row, update @moq/ui-core description
- Create doc pages: @moq/watch.md, @moq/publish.md, @moq/ui-core.md (fix dead links)

Milestone 7 — Clean up @moq/hang:
- Remove unused deps: comlink, async-mutex (only used by extracted watch/publish)
- Rewrite js/hang/README.md for core-only scope (catalog, container, support)
- Rewrite doc/js/@moq/hang/index.md for core-only scope
- Update README.md @moq/hang description in package table

All packages pass bun run check (TypeScript + VitePress build, zero dead links).
The <hang-watch-ui> and <hang-publish-ui> elements work by discovering a
nested <hang-watch> / <hang-publish> child — they don't accept url/path
attributes directly. Updated all doc examples to show the correct usage:

- doc/js/@moq/watch.md
- doc/js/@moq/publish.md
- doc/js/@moq/hang/watch.md
- doc/js/@moq/hang/publish.md
- Container includes both CMAF (fMP4) and Legacy formats, not just CMAF
- Fix CMAF API names in code examples to match actual exports
- Fix Utilities description: hex encoding, Opus polyfill, latency computation, browser workarounds
- Fix hang-watch-ui / hang-publish-ui examples to show correct wrapping pattern
  (they discover a nested child element, not accept url/path attributes directly)

Updated: doc/js/@moq/hang/index.md, js/hang/README.md,
         doc/js/@moq/watch.md, doc/js/@moq/publish.md,
         doc/js/@moq/hang/watch.md, doc/js/@moq/hang/publish.md
- tsconfig.json now includes src/ui with SolidJS JSX settings, used by
  the IDE and check script for full type coverage
- tsconfig.build.json excludes src/ui for tsc -b declaration emit
  (Vite handles UI compilation)
- Added vite-env.d.ts for Vite-specific import types (?raw, ?inline)

Affected packages: @moq/watch, @moq/publish
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 12, 2026

Walkthrough

This pull request restructures the package architecture by separating the monolithic @moq/hang-ui package into three distinct packages: @moq/ui-core (containing shared UI primitives), @moq/watch (for subscribing to and rendering broadcasts), and @moq/publish (for publishing media). The @moq/hang package is refactored to focus on core utilities—Catalog, Container, and Support—rather than media-specific watch/publish functionality. All documentation is updated to reflect new module import paths and package relationships. Internal modules across @moq/watch and @moq/publish are updated to import from the refactored @moq/hang core package using scoped imports instead of relative paths.

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title directly and clearly describes the main change: splitting UI components from @moq/hang into separate dedicated packages (@moq/ui-core, @moq/watch, @moq/publish).
Description check ✅ Passed The description is comprehensive and directly related to the changeset, explaining the rationale, new packages created, removed code from @moq/hang, build changes, documentation updates, and Nix modifications.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (6)
js/ui-core/vite.config.ts (1)

14-16: ⚠️ Potential issue | 🟡 Minor

Add @moq/watch to rollupOptions.external.

The package @moq/watch is imported in stats/types.ts for type definitions but is not listed in the external array, which could cause it to be bundled into the library output instead of being treated as a peer dependency.

doc/js/@moq/hang/index.md (1)

80-86: ⚠️ Potential issue | 🟡 Minor

Stale links in "Next Steps" section.

Lines 82–83 still point to /js/@moq/hang/watch and /js/@moq/hang/publish, but the "Related Packages" section above correctly links to /js/@moq/watch and /js/@moq/publish. These should be updated to match.

Proposed fix
 ## Next Steps
 
-- Learn about [watching streams](/js/@moq/hang/watch)
-- Learn about [publishing streams](/js/@moq/hang/publish)
+- Learn about [watching streams](/js/@moq/watch)
+- Learn about [publishing streams](/js/@moq/publish)
 - Use [Web Components](/js/env/web)
 - Use [`@moq/lite`](/js/@moq/lite) for custom protocols
 - View [code examples](https://github.com/moq-dev/moq/tree/main/js)
doc/js/@moq/hang/watch.md (2)

60-85: ⚠️ Potential issue | 🟡 Minor

JavaScript API examples still use old @moq/hang import paths.

The Web Component and React/SolidJS sections are updated to @moq/watch, but the JS API examples on lines 61–85 and 130–141 still use import * as Hang from "@moq/hang" and Hang.Watch.Broadcast(...). These should be updated to use @moq/watch to match the rest of this file.

Proposed fix for lines 60-85
 ```typescript
-import * as Hang from "@moq/hang";
+import * as Watch from "@moq/watch";
 
-const connection = new Hang.Connection("https://relay.example.com/anon");
+const connection = new Hang.Connection("https://relay.example.com/anon"); // Connection still from `@moq/hang`
 
-const watch = new Hang.Watch.Broadcast(connection, {
+const watch = new Watch.Broadcast(connection, {
     enabled: true,
     name: "alice",

128-141: ⚠️ Potential issue | 🟡 Minor

Same stale Hang.Watch.Broadcast reference in the Track Selection example.

-const watch = new Hang.Watch.Broadcast(connection, {
+const watch = new Watch.Broadcast(connection, {
doc/js/@moq/hang/publish.md (1)

60-87: ⚠️ Potential issue | 🟡 Minor

JavaScript API examples still reference @moq/hang instead of @moq/publish.

Same issue as in the watch doc — the Web Component and framework integration sections are updated to @moq/publish, but the JS API examples throughout (lines 62, 66, 94, 106, 141, 162, 176) still use import * as Hang from "@moq/hang" and Hang.Publish.Broadcast(...). These should be migrated to @moq/watch / @moq/publish for consistency.

doc/js/index.md (1)

25-37: ⚠️ Potential issue | 🟡 Minor

@moq/hang description is stale after the reorganization.

The PR refocuses @moq/hang on core primitives (Catalog, Container, Support), but Lines 29–35 still describe it as a "High-level media library with Web Components." Web Components are now in @moq/watch and @moq/publish. Update this section to reflect the new scope.

🤖 Fix all issues with AI agents
In `@js/publish/README.md`:
- Around line 95-100: The License links in the "## License" section of
js/publish/README.md point to LICENSE-APACHE and LICENSE-MIT in the current
folder but those files live at the repo root; update the links to use the
correct relative paths ("../../LICENSE-APACHE" and "../../LICENSE-MIT") or
alternatively copy the license files into js/publish/ so the existing references
resolve; locate the "## License" header and change the two link targets for
LICENSE-APACHE and LICENSE-MIT accordingly.

In `@js/publish/vite.config.ts`:
- Around line 14-16: The rollupOptions.external array currently only lists
["@moq/hang","@moq/lite","@moq/signals","@moq/ui-core"] and misses externalizing
Solid libraries used by the UI entry points; update the rollupOptions.external
setting (in vite.config.ts) to include "solid-js", "solid-js/web", and
"solid-element" so those runtimes are not bundled into the library output (do
not add "solid-js/store" since it's not used).

In `@js/ui-core/src/stats/types.ts`:
- Around line 3-4: The file imports type symbols from "@moq/watch" (imported as
Watch) creating a circular package dependency between `@moq/ui-core` and
`@moq/watch`; remove the type import from js/ui-core/src/stats/types.ts by moving
the shared types (stats and any backend interfaces referenced here) into
`@moq/ui-core` itself or into a new dedicated package (e.g., `@moq/types`), then
update consumers: export the moved types from the new location and change
`@moq/watch` (and any other package) to import those types from `@moq/ui-core` or
`@moq/types` instead; ensure js/ui-core/src/stats/types.ts no longer references
Watch (or Hang) from `@moq/watch` so dependency flows one-way (watch → ui-core).
🧹 Nitpick comments (5)
js/watch/package.json (1)

28-37: Consider declaring solid-js and solid-element as peerDependencies.

These packages provide the runtime for the Solid-based web components exported via ./ui and ./element. Listing them only as devDependencies means consumers won't be prompted to install them, and the library build may either bundle them (causing duplicates) or fail at runtime. The same applies to js/publish/package.json.

js/ui-core/package.json (1)

22-34: solid-js should be a peer dependency since exports point to raw source files.

The "." export resolves to ./src/index.ts (unbundled source), so consumers must have solid-js available at build time. Keeping it only in devDependencies means consumers won't be warned if it's missing.

Proposed fix
 "peerDependencies": {
 	"@moq/hang": "workspace:^0.1.0",
 	"@moq/signals": "workspace:^0.1.0",
-	"@moq/watch": "workspace:^0.1.0"
+	"@moq/watch": "workspace:^0.1.0",
+	"solid-js": "^1.9.10"
 },
doc/js/@moq/publish.md (1)

15-19: Consider removing the npm alternative per project guidelines.

The coding guidelines specify using bun for all package management. If this doc targets external consumers who may use npm, this is fine — but it's inconsistent with the project convention.

As per coding guidelines: "Use bun for all TypeScript/JavaScript package management and script execution (not npm, yarn, or pnpm)".

js/docs/restructure-plan.md (1)

34-44: Missing language specifier on fenced code block.

The dependency graph code block should specify a language (e.g., text or plaintext) to satisfy linting and improve rendering.

-```
+```text
 `@moq/lite`  ←─────────────────────────────┐
js/ui-core/src/stats/types.ts (1)

21-31: The TODO on line 28 is worth addressing now.

The comment asks whether to use Watch.Backend instead of separately typing Watch.Audio.Backend and Watch.Video.Backend in ProviderProps. Since this file is being actively refactored, it would be a good time to clarify the intent and either resolve the TODO or convert it to a tracked issue.

Would you like me to open an issue to track this TODO?

Comment on lines +14 to +16
rollupOptions: {
external: ["@moq/hang", "@moq/lite", "@moq/signals", "@moq/ui-core"],
},
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# First, check package.json to see if solid-js is a dev or regular dependency
echo "=== Checking package.json dependencies ==="
jq '.dependencies, .devDependencies' package.json | grep -A 5 -B 5 "solid" || echo "Checking structure..."

echo ""
echo "=== Finding all vite.config files ==="
fd "vite.config" --type f

echo ""
echo "=== Checking current external configurations in vite.config files ==="
fd "vite.config" --type f -x cat {}

echo ""
echo "=== Checking for solid imports in source files ==="
rg "from ['\"]solid" js/publish/src/ js/watch/src/ js/ui-core/src/ --type ts --type tsx -n 2>/dev/null || echo "No direct matches found"

Repository: moq-dev/moq

Length of output: 2434


🏁 Script executed:

#!/bin/bash
# Check the full dependency structure
echo "=== Root package.json dependencies and devDependencies ==="
cat package.json | jq '.dependencies, .devDependencies' 2>/dev/null | head -100

echo ""
echo "=== Check workspace packages ==="
# Look for workspace packages that might have their own package.json
fd "package.json" js/ --max-depth 2

echo ""
echo "=== Search for solid in entire js directory ==="
rg "solid" js/ --type json --type ts --type tsx -c 2>/dev/null | head -20

echo ""
echo "=== Check js/publish/src for all imports ==="
find js/publish/src -type f \( -name "*.ts" -o -name "*.tsx" \) -exec echo "File: {}" \; -exec head -30 {} \;

Repository: moq-dev/moq

Length of output: 32592


🏁 Script executed:

#!/bin/bash
# Check individual package.json files for solid dependencies
echo "=== js/publish/package.json ==="
cat js/publish/package.json | jq '.dependencies, .devDependencies, .peerDependencies' 2>/dev/null

echo ""
echo "=== js/ui-core/package.json ==="
cat js/ui-core/package.json | jq '.dependencies, .devDependencies, .peerDependencies' 2>/dev/null

echo ""
echo "=== js/watch/package.json ==="
cat js/watch/package.json | jq '.dependencies, .devDependencies, .peerDependencies' 2>/dev/null

echo ""
echo "=== List all solid imports found ==="
rg "from ['\"]solid" js/publish/src/ js/watch/src/ js/ui-core/src/ --type tsx --type ts -A 1 2>/dev/null | head -50

Repository: moq-dev/moq

Length of output: 1252


🏁 Script executed:

#!/bin/bash
# Check which solid-js entry points are imported
echo "=== Checking for solid-js/store imports ==="
rg "solid-js/store" js/ --type tsx --type ts 2>/dev/null || echo "No solid-js/store imports found"

echo ""
echo "=== All solid entry point imports ==="
rg "from ['\"]solid" js/ --type tsx --type ts -o 2>/dev/null | sort -u

echo ""
echo "=== Check if any dist files exist ==="
find js/publish/dist js/watch/dist js/ui-core/dist -type f 2>/dev/null | head -20 || echo "No dist files found"

Repository: moq-dev/moq

Length of output: 208


🏁 Script executed:

#!/bin/bash
# Look at the actual imports in UI component files
echo "=== Solid imports in js/publish/src/ui/index.tsx ==="
grep -n "from ['\"]solid" js/publish/src/ui/index.tsx

echo ""
echo "=== Solid imports in js/publish/src/ui/context.tsx ==="
grep -n "from ['\"]solid" js/publish/src/ui/context.tsx

echo ""
echo "=== All files with solid imports ==="
grep -r "from ['\"]solid" js/publish/src/ui/ js/watch/src/ui/ 2>/dev/null | cut -d: -f1 | sort -u

echo ""
echo "=== Summary of what is exported from vite config entry points ==="
echo "js/publish builds ui/index entry which exports:"
head -50 js/publish/src/ui/index.tsx | tail -30

echo ""
echo "js/watch builds ui/index entry which exports:"
head -50 js/watch/src/ui/index.tsx | tail -30

Repository: moq-dev/moq

Length of output: 2847


Externalize solid-js and solid-element in vite.config for UI builds.

Both js/publish and js/watch export UI entry points that depend on solid-js and solid-element (imported as customElement, createSignal, Show, etc.), but these devDependencies are not externalized. Bundling them into the library output will cause duplicate runtimes for consumers. Include only the imported entry points: "solid-js", "solid-js/web", and "solid-element" (omit solid-js/store, which is not used).

Proposed fix
 		rollupOptions: {
-			external: ["@moq/hang", "@moq/lite", "@moq/signals", "@moq/ui-core"],
+			external: ["@moq/hang", "@moq/lite", "@moq/signals", "@moq/ui-core", "solid-js", "solid-js/web", "solid-element"],
 		},
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
rollupOptions: {
external: ["@moq/hang", "@moq/lite", "@moq/signals", "@moq/ui-core"],
},
rollupOptions: {
external: ["@moq/hang", "@moq/lite", "@moq/signals", "@moq/ui-core", "solid-js", "solid-js/web", "solid-element"],
},
🤖 Prompt for AI Agents
In `@js/publish/vite.config.ts` around lines 14 - 16, The rollupOptions.external
array currently only lists
["@moq/hang","@moq/lite","@moq/signals","@moq/ui-core"] and misses externalizing
Solid libraries used by the UI entry points; update the rollupOptions.external
setting (in vite.config.ts) to include "solid-js", "solid-js/web", and
"solid-element" so those runtimes are not bundled into the library output (do
not add "solid-js/store" since it's not used).

@jdreetz jdreetz marked this pull request as draft February 12, 2026 16:39
- Replace @moq/watch and @moq/hang imports in ui-core/src/stats/types.ts
  with structural interfaces (Peekable, AudioBackend, VideoBackend)
- Remove @moq/watch and @moq/hang from ui-core peerDependencies
- Fix LICENSE-APACHE and LICENSE-MIT paths in publish and watch READMEs
@jdreetz jdreetz changed the title Re org UI components Split UI components into dedicated packages Feb 12, 2026
The ring-buffer test file was moved to @moq/watch during the
reorganization but the test script stayed in @moq/hang, causing
CI to fail with 'No tests found'.
@jdreetz jdreetz marked this pull request as ready for review February 12, 2026 18:21
@jdreetz jdreetz requested a review from kixelated February 12, 2026 18:21
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@js/watch/README.md`:
- Around line 101-102: Update the two license URLs in README lines containing
"Apache License, Version 2.0" and "MIT license" to use HTTPS instead of HTTP;
replace "http://www.apache.org/licenses/LICENSE-2.0" with
"https://www.apache.org/licenses/LICENSE-2.0" and
"http://opensource.org/licenses/MIT" with "https://opensource.org/licenses/MIT"
so both links are secure and consistent.
🧹 Nitpick comments (4)
js/ui-core/src/stats/types.ts (2)

7-9: Consider exporting Peekable<T> for consumer convenience.

Peekable<T> is used in all exported interfaces (AudioBackend, VideoBackend) but isn't exported itself. Consumers who need to construct objects conforming to these interfaces (e.g., in tests or custom backends) would benefit from being able to reference this type directly rather than re-declaring it.

♻️ Suggested change
-interface Peekable<T> {
+export interface Peekable<T> {
 	peek(): T;
 }

21-27: source.track typed as Peekable<unknown> loses type safety.

Other fields use specific shapes (e.g., config has sampleRate, numberOfChannels, codec), but track is Peekable<unknown>. If stats providers actually read properties from the track value, this forces unsafe casts downstream. If the track is only checked for presence/absence, unknown is acceptable.

js/ui-core/src/index.ts (1)

4-4: AudioBackend and VideoBackend are not re-exported but are part of the public API surface.

ProviderProps references AudioBackend and VideoBackend, so consumers who need to type individual backend parameters (e.g., passing just the audio backend to a helper) can't import those types from @moq/ui-core.

♻️ Suggested change
-export type { KnownStatsProviders, ProviderContext, ProviderProps } from "./stats/types";
+export type { AudioBackend, KnownStatsProviders, Peekable, ProviderContext, ProviderProps, VideoBackend } from "./stats/types";
js/watch/src/ui/components/BufferControl.tsx (1)

39-43: Consider extracting color literals to named constants.

The hex color strings are used as semantic indicators (red = buffering, yellow = gap, green = healthy) but are inline magic values. Named constants would improve readability.

As per coding guidelines: "Avoid using magic numbers; use named constants instead."

♻️ Suggested change
+const BUFFER_COLOR_BUFFERING = "#f87171"; // red
+const BUFFER_COLOR_GAP = "#facc15";       // yellow
+const BUFFER_COLOR_HEALTHY = "#4ade80";   // green
+
 const rangeColor = (index: number, isBuffering: boolean) => {
-	if (isBuffering) return "#f87171"; // red
-	if (index > 0) return "#facc15"; // yellow
-	return "#4ade80"; // green
+	if (isBuffering) return BUFFER_COLOR_BUFFERING;
+	if (index > 0) return BUFFER_COLOR_GAP;
+	return BUFFER_COLOR_HEALTHY;
 };

Comment on lines +101 to +102
- Apache License, Version 2.0 ([LICENSE-APACHE](../../LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license ([LICENSE-MIT](../../LICENSE-MIT) or http://opensource.org/licenses/MIT)
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Use HTTPS for license URLs.
The license links currently use http. Prefer https for security and consistency.

Suggested fix
--   Apache License, Version 2.0 ([LICENSE-APACHE](../../LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
--   MIT license ([LICENSE-MIT](../../LICENSE-MIT) or http://opensource.org/licenses/MIT)
+-   Apache License, Version 2.0 ([LICENSE-APACHE](../../LICENSE-APACHE) or https://www.apache.org/licenses/LICENSE-2.0)
+-   MIT license ([LICENSE-MIT](../../LICENSE-MIT) or https://opensource.org/licenses/MIT)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- Apache License, Version 2.0 ([LICENSE-APACHE](../../LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license ([LICENSE-MIT](../../LICENSE-MIT) or http://opensource.org/licenses/MIT)
- Apache License, Version 2.0 ([LICENSE-APACHE](../../LICENSE-APACHE) or https://www.apache.org/licenses/LICENSE-2.0)
- MIT license ([LICENSE-MIT](../../LICENSE-MIT) or https://opensource.org/licenses/MIT)
🤖 Prompt for AI Agents
In `@js/watch/README.md` around lines 101 - 102, Update the two license URLs in
README lines containing "Apache License, Version 2.0" and "MIT license" to use
HTTPS instead of HTTP; replace "http://www.apache.org/licenses/LICENSE-2.0" with
"https://www.apache.org/licenses/LICENSE-2.0" and
"http://opensource.org/licenses/MIT" with "https://opensource.org/licenses/MIT"
so both links are secure and consistent.

@kixelated
Copy link
Collaborator

Oh sorry, the Nix stuff should have been fixed by #952, but it's still good to have. The quiche backend doesn't quite work so I disabled it by default.

"./container": "./src/container/index.ts",
"./util/hex": "./src/util/hex.ts",
"./util/libav": "./src/util/libav.ts",
"./util/hacks": "./src/util/hacks.ts",
Copy link
Collaborator

Choose a reason for hiding this comment

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

Feels bad. Maybe just export util?

We could make separate packages for stuff like libav I guess.
Other stuff you could probably just copy-paste (ex. hex). Not a huge deal.

"rootDir": ".",
"outDir": "dist",
"jsx": "preserve",
"jsxImportSource": "solid-js"
Copy link
Collaborator

Choose a reason for hiding this comment

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

hmm maybe this should be in ui instead.

@@ -1,18 +1,17 @@
{
"name": "@moq/hang-ui",
"name": "@moq/ui-core",
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit: @moq/theme?

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