chore: move packages/web → apps/web
Web is a deployable SPA, not a library — no @meshtastic scope, no exports map, no npm/JSR publish target, no other workspace member depends on it. Conventional pnpm/Turbo/Nx layout puts deployables under apps/ and libraries under packages/. Doing the move now (after PR #9 / #10 / unread / useConnections refactor land but before Phase C ships) so the lib-only packages/* directory remains stable as we delete packages/core. Mechanics: - pnpm-workspace.yaml: add `apps/*` to packages. - git mv packages/web apps/web (entire directory tree). - vite.config.ts uses process.cwd(), so no internal path edits needed. - pnpm filter commands still resolve by package name (`pnpm --filter meshtastic-web run build`) — no script changes. External-path consumers updated: - README.md table row. - tsconfig.json reference. - 7 GH workflows (pr.yml, nightly.yml, release-web.yml, the three crowdin-*.yml, release-packages.yml). The packages/release-packages.yml `packages/* | grep -v packages/web` filter is now redundant since web isn't in packages/* anymore — it collapses to plain `ls -d packages/*`. Verified: web build clean, web 236 / sdk 65 / sdk-react 8 / storage 30 tests all pass.
2
.github/workflows/crowdin-download.yml
vendored
@@ -17,7 +17,7 @@ jobs:
|
||||
uses: crowdin/github-action@v2
|
||||
with:
|
||||
base_url: "https://meshtastic.crowdin.com/api/v2"
|
||||
config: "./packages/web/crowdin.yml"
|
||||
config: "./apps/web/crowdin.yml"
|
||||
upload_sources: false
|
||||
upload_translations: false
|
||||
download_translations: true
|
||||
|
||||
4
.github/workflows/crowdin-upload-sources.yml
vendored
@@ -5,7 +5,7 @@ on:
|
||||
# Monitor all .json files within the /i18n/locales/en/ directory.
|
||||
# This ensures the workflow triggers if any the English namespace files are modified on the main branch.
|
||||
paths:
|
||||
- "/packages/web/public/i18n/locales/en/*.json"
|
||||
- "/apps/web/public/i18n/locales/en/*.json"
|
||||
branches: [main]
|
||||
workflow_dispatch: # Allow manual triggering
|
||||
|
||||
@@ -21,7 +21,7 @@ jobs:
|
||||
uses: crowdin/github-action@v2
|
||||
with:
|
||||
base_url: "https://meshtastic.crowdin.com/api/v2"
|
||||
config: "./packages/web/crowdin.yml"
|
||||
config: "./apps/web/crowdin.yml"
|
||||
upload_sources: true
|
||||
upload_translations: false
|
||||
download_translations: false
|
||||
|
||||
@@ -15,7 +15,7 @@ jobs:
|
||||
uses: crowdin/github-action@v2
|
||||
with:
|
||||
base_url: "https://meshtastic.crowdin.com/api/v2"
|
||||
config: "./packages/web/crowdin.yml"
|
||||
config: "./apps/web/crowdin.yml"
|
||||
upload_sources: false
|
||||
upload_translations: true
|
||||
download_translations: false
|
||||
|
||||
12
.github/workflows/nightly.yml
vendored
@@ -39,18 +39,18 @@ jobs:
|
||||
run: pnpm run test
|
||||
|
||||
- name: Build web package
|
||||
working-directory: packages/web
|
||||
working-directory: apps/web
|
||||
run: pnpm run build
|
||||
|
||||
- name: Package output
|
||||
working-directory: packages/web
|
||||
working-directory: apps/web
|
||||
run: pnpm run package
|
||||
|
||||
- name: Upload compressed build (artifact)
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: web-build-nightly
|
||||
path: packages/web/dist/build.tar
|
||||
path: apps/web/dist/build.tar
|
||||
if-no-files-found: error
|
||||
|
||||
- name: Compute tags and labels
|
||||
@@ -66,8 +66,8 @@ jobs:
|
||||
|
||||
# Try to use latest release tag if it exists; fallback to package version; else date
|
||||
LATEST_TAG="$(gh release view --json tagName --jq .tagName 2>/dev/null || true)"
|
||||
if [ -z "$LATEST_TAG" ] && [ -f packages/web/package.json ]; then
|
||||
LATEST_TAG="v$(jq -r .version packages/web/package.json)"
|
||||
if [ -z "$LATEST_TAG" ] && [ -f apps/web/package.json ]; then
|
||||
LATEST_TAG="v$(jq -r .version apps/web/package.json)"
|
||||
fi
|
||||
|
||||
if [ -n "${LATEST_TAG:-}" ] && [ "$LATEST_TAG" != "vnull" ]; then
|
||||
@@ -91,7 +91,7 @@ jobs:
|
||||
uses: redhat-actions/buildah-build@v2
|
||||
with:
|
||||
containerfiles: |
|
||||
./packages/web/infra/Containerfile
|
||||
./apps/web/infra/Containerfile
|
||||
image: ${{ env.REGISTRY_IMAGE }}
|
||||
tags: |
|
||||
${{ steps.meta.outputs.moving_tag }}
|
||||
|
||||
2
.github/workflows/pr.yml
vendored
@@ -51,4 +51,4 @@ jobs:
|
||||
run: pnpm run test
|
||||
|
||||
- name: Build web package
|
||||
run: pnpm --filter "./packages/web" run build
|
||||
run: pnpm --filter "./apps/web" run build
|
||||
|
||||
2
.github/workflows/release-packages.yml
vendored
@@ -46,7 +46,7 @@ jobs:
|
||||
run: |
|
||||
set -euo pipefail
|
||||
if [ "${{ github.event.inputs.packages }}" = "all" ] || [ -z "${{ github.event.inputs.packages }}" ]; then
|
||||
mapfile -t TARGETS < <(ls -d packages/* | grep -v 'packages/web')
|
||||
mapfile -t TARGETS < <(ls -d packages/*)
|
||||
else
|
||||
IFS=',' read -ra TARGETS <<< "${{ github.event.inputs.packages }}"
|
||||
TARGETS=("${TARGETS[@]/#/packages/}")
|
||||
|
||||
10
.github/workflows/release-web.yml
vendored
@@ -51,25 +51,25 @@ jobs:
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Build web package
|
||||
working-directory: packages/web
|
||||
working-directory: apps/web
|
||||
run: pnpm run build
|
||||
|
||||
- name: Create release archive
|
||||
working-directory: packages/web
|
||||
working-directory: apps/web
|
||||
run: pnpm run package
|
||||
|
||||
- name: Upload archive (artifact)
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: web-build
|
||||
path: packages/web/dist/build.tar
|
||||
path: apps/web/dist/build.tar
|
||||
if-no-files-found: error
|
||||
|
||||
- name: Attach archive to GitHub Release
|
||||
if: ${{ github.event_name == 'release' || inputs.attach_to_release == true }}
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
files: packages/web/dist/build.tar
|
||||
files: apps/web/dist/build.tar
|
||||
tag_name: ${{ github.event_name == 'release' && github.event.release.tag_name || inputs.tag_name }}
|
||||
fail_on_unmatched_files: true
|
||||
env:
|
||||
@@ -134,7 +134,7 @@ jobs:
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
file: ./packages/web/infra/Containerfile
|
||||
file: ./apps/web/infra/Containerfile
|
||||
platforms: linux/amd64,linux/arm64,linux/arm/v7
|
||||
push: ${{ github.event_name == 'release' || (github.event_name == 'workflow_dispatch' && inputs.tag_name != '') }}
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
|
||||
3
.gitignore
vendored
@@ -18,3 +18,6 @@ packages/protobufs/packages/ts/dist
|
||||
*.pem
|
||||
*.crt
|
||||
*.key
|
||||
|
||||
# Claude Code session locks
|
||||
.claude/
|
||||
|
||||
2
.vscode/extensions.json
vendored
@@ -1,3 +1,3 @@
|
||||
{
|
||||
"recommendations": ["bradlc.vscode-tailwindcss", "biomejs.biome"]
|
||||
"recommendations": ["bradlc.vscode-tailwindcss", "oxc.oxc-vscode"]
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ All projects live under `packages/`.
|
||||
| --- | --- |
|
||||
| `packages/sdk` | Framework-agnostic TypeScript SDK. Domain-driven feature slices (device, chat, nodes, channels, config, telemetry, position, traceroute, files) built around a `MeshClient` orchestrator with `@preact/signals-core` reactive state. |
|
||||
| `packages/sdk-react` | React hooks + `MeshProvider` on top of `@meshtastic/sdk`. Wraps signals in `useSyncExternalStore` for concurrent-safe renders. |
|
||||
| `packages/web` | Reference React web client. Hosted at [client.meshtastic.org](https://client.meshtastic.org). |
|
||||
| `apps/web` | Reference React web client. Hosted at [client.meshtastic.org](https://client.meshtastic.org). |
|
||||
| `packages/ui` | Shared Radix + Tailwind component library. |
|
||||
| `packages/protobufs` | Generated TypeScript stubs from [`meshtastic/protobufs`](https://github.com/meshtastic/protobufs), produced via `buf generate`. Source of truth for every wire-level type. |
|
||||
| `packages/transport-http` | HTTP transport for devices exposing a network interface. |
|
||||
|
||||
@@ -19,8 +19,8 @@ Tests live in five tiers. Each PR should add coverage at the **lowest level that
|
||||
|
||||
| Package | Required floor | Notes |
|
||||
| --- | --- | --- |
|
||||
| `packages/sdk` core | every primitive (signals, EventBus, Queue, packet-codec, identifiers) has a unit test; lifecycle covered by `MeshClient.test.ts` | adopt `c8` thresholds once stable |
|
||||
| `packages/sdk` features/* | each slice ships: 1 domain invariant test, 1 use-case test against fake transport, 1 mapper round-trip (where mappers exist) | Integration covered by `tests/integration/fake-transport.test.ts` |
|
||||
| `packages/sdk/core` | every primitive (signals, EventBus, Queue, packet-codec, identifiers) has a unit test; lifecycle covered by `MeshClient.test.ts` | adopt `c8` thresholds once stable |
|
||||
| `packages/sdk/features/*` | each slice ships: 1 domain invariant test, 1 use-case test against fake transport, 1 mapper round-trip (where mappers exist) | Integration covered by `tests/integration/fake-transport.test.ts` |
|
||||
| `packages/sdk-react` | each public hook has a `renderHook` test that asserts initial render + re-render on signal change | uses jsdom; provider wrapper required |
|
||||
| `packages/sdk-storage-sqlocal` | every repository method tested against sql.js in-memory; **at least one OPFS-real test per repo** runs in browser mode | sql.js validates SQL correctness; OPFS validates VFS / Worker plumbing |
|
||||
| `packages/transport-*` | minimum: framing round-trip, disconnect cleans up streams, error path emits status | low-level; ship as is |
|
||||
|
||||
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 3.1 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 102 KiB After Width: | Height: | Size: 102 KiB |
|
Before Width: | Height: | Size: 77 KiB After Width: | Height: | Size: 77 KiB |
|
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 5.3 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.2 KiB |
|
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 5.0 KiB |
|
Before Width: | Height: | Size: 7.4 KiB After Width: | Height: | Size: 7.4 KiB |
|
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 5.2 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 95 KiB After Width: | Height: | Size: 95 KiB |
|
Before Width: | Height: | Size: 95 KiB After Width: | Height: | Size: 95 KiB |
|
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 47 KiB |
|
Before Width: | Height: | Size: 9.5 KiB After Width: | Height: | Size: 9.5 KiB |
|
Before Width: | Height: | Size: 102 KiB After Width: | Height: | Size: 102 KiB |
|
Before Width: | Height: | Size: 86 KiB After Width: | Height: | Size: 86 KiB |
|
Before Width: | Height: | Size: 6.8 KiB After Width: | Height: | Size: 6.8 KiB |
|
Before Width: | Height: | Size: 164 KiB After Width: | Height: | Size: 164 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 128 KiB After Width: | Height: | Size: 128 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 89 KiB After Width: | Height: | Size: 89 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 8.8 KiB After Width: | Height: | Size: 8.8 KiB |
|
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 4.5 KiB |
|
Before Width: | Height: | Size: 85 KiB After Width: | Height: | Size: 85 KiB |
|
Before Width: | Height: | Size: 131 KiB After Width: | Height: | Size: 131 KiB |
|
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 7.7 KiB After Width: | Height: | Size: 7.7 KiB |
|
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 38 KiB |
|
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 9.5 KiB After Width: | Height: | Size: 9.5 KiB |
|
Before Width: | Height: | Size: 9.4 KiB After Width: | Height: | Size: 9.4 KiB |
|
Before Width: | Height: | Size: 110 KiB After Width: | Height: | Size: 110 KiB |
|
Before Width: | Height: | Size: 148 KiB After Width: | Height: | Size: 148 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |