Browse Source

Merge branch 'meshtastic:main' into persistent-nodedb

pull/780/head
Jeremy Gallant 11 months ago
committed by GitHub
parent
commit
a7ddd8e263
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 14
      .github/workflows/ci.yml
  2. 85
      .github/workflows/nightly.yml
  3. 52
      .github/workflows/pr.yml
  4. 130
      .github/workflows/release-packages.yml
  5. 58
      .github/workflows/release-web.yml
  6. 63
      .github/workflows/update-stable-from-master.yml
  7. 1
      .gitignore
  8. 14
      package.json
  9. 11
      packages/core/package.json
  10. 7
      packages/transport-deno/package.json
  11. 18
      packages/transport-http/package.json
  12. 28
      packages/transport-node-serial/README.md
  13. 1
      packages/transport-node-serial/mod.ts
  14. 39
      packages/transport-node-serial/package.json
  15. 87
      packages/transport-node-serial/src/transport.ts
  16. 18
      packages/transport-node-serial/tsconfig.json
  17. 5
      packages/transport-node/package.json
  18. 12
      packages/transport-web-bluetooth/package.json
  19. 12
      packages/transport-web-serial/package.json
  20. 150
      packages/web/CONTRIBUTIONS.md
  21. 89
      packages/web/infra/default.conf
  22. 1
      packages/web/package.json
  23. 2
      packages/web/public/i18n/locales/bg-BG/common.json
  24. 24
      packages/web/public/i18n/locales/bg-BG/deviceConfig.json
  25. 20
      packages/web/public/i18n/locales/bg-BG/dialog.json
  26. 12
      packages/web/public/i18n/locales/bg-BG/messages.json
  27. 4
      packages/web/public/i18n/locales/bg-BG/moduleConfig.json
  28. 4
      packages/web/public/i18n/locales/bg-BG/nodes.json
  29. 10
      packages/web/public/i18n/locales/bg-BG/ui.json
  30. 1
      packages/web/public/i18n/locales/en/commandPalette.json
  31. 5
      packages/web/public/i18n/locales/en/dialog.json
  32. 8
      packages/web/src/components/CommandPalette/index.tsx
  33. 331
      pnpm-lock.yaml

14
.github/workflows/ci.yml

@ -15,16 +15,18 @@ jobs:
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: latest
- name: Setup Node.js - name: Setup Node.js
uses: actions/setup-node@v4 uses: actions/setup-node@v4
with: with:
node-version: 22 node-version: 22
cache: pnpm
- name: Setup pnpm cache-dependency-path: '**/pnpm-lock.yaml'
uses: pnpm/action-setup@v4
with:
version: latest
- name: Setup Deno - name: Setup Deno
uses: denoland/setup-deno@v2 uses: denoland/setup-deno@v2
@ -59,7 +61,7 @@ jobs:
if [[ -f "$pkg_dir/package.json" ]] && [[ "$pkg_dir" != "packages/web" ]]; then if [[ -f "$pkg_dir/package.json" ]] && [[ "$pkg_dir" != "packages/web" ]]; then
echo "🔧 Building with pnpm: $pkg_dir" echo "🔧 Building with pnpm: $pkg_dir"
(cd "$pkg_dir" && pnpm install && pnpm run build:npm) (cd "$pkg_dir" && pnpm install --frozen-lockfile && pnpm run build:npm)
else else
echo "⚠️ Skipping $pkg_dir (web package or no package.json)" echo "⚠️ Skipping $pkg_dir (web package or no package.json)"
fi fi

85
.github/workflows/nightly.yml

@ -1,91 +1,101 @@
name: "Nightly Release" name: Nightly Release
on: on:
schedule: schedule:
- cron: "0 5 * * *" # Run every day at 5am UTC - cron: "0 5 * * *" # 05:00 UTC daily
workflow_dispatch: {} # allow manual runs too
permissions: permissions:
contents: write contents: read
packages: write packages: write
env:
REGISTRY_IMAGE: ghcr.io/${{ github.repository }}
jobs: jobs:
nightly-build-and-push: nightly-build-and-push:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
# Node + pnpm (with built-in cache)
- name: Setup Node.js - name: Setup Node.js
uses: actions/setup-node@v4 uses: actions/setup-node@v4
with: with:
node-version: 22 node-version: 22
cache: pnpm
cache-dependency-path: '**/pnpm-lock.yaml'
- name: Setup pnpm - name: Setup pnpm
uses: pnpm/action-setup@v4 uses: pnpm/action-setup@v4
with: with:
version: latest version: latest
- name: Cache pnpm dependencies - name: Install deps (root)
uses: actions/cache@v4 run: pnpm install --frozen-lockfile
with:
path: |
~/.pnpm-store
packages/web/node_modules
key: ${{ runner.os }}-pnpm-${{ hashFiles('packages/web/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-
- name: Run tests - name: Run tests
run: pnpm run test run: pnpm run test
- name: Install Dependencies - name: Build web package
working-directory: packages/web
run: pnpm install
- name: Build Package
working-directory: packages/web working-directory: packages/web
run: pnpm run build run: pnpm run build
- name: Package Output - name: Package output
working-directory: packages/web working-directory: packages/web
run: pnpm run package run: pnpm run package
- name: Archive compressed build - name: Upload compressed build (artifact)
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
with: with:
name: build name: web-build-nightly
path: packages/web/dist/build.tar path: packages/web/dist/build.tar
if-no-files-found: error
- name: Get latest release version - name: Determine nightly tag
id: get_release id: meta
shell: bash
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: | run: |
LATEST_TAG=$(curl -sL \ set -euo pipefail
-H "Accept: application/vnd.github+json" \ DATE="$(date -u +%Y%m%d)"
-H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \ SHORTSHA="$(git rev-parse --short=12 HEAD)"
https://api.github.com/repos/${{ github.repository }}/releases/latest | jq -r ".tag_name") # Try to use latest release tag if it exists; fallback to package version; else date
# Fallback to a default if no release is found LATEST_TAG="$(gh release view --json tagName --jq .tagName 2>/dev/null || true)"
if [ -z "$LATEST_TAG" ]; then if [ -z "$LATEST_TAG" ] && [ -f packages/web/package.json ]; then
LATEST_TAG="2.6.0" LATEST_TAG="v$(jq -r .version packages/web/package.json)"
fi fi
echo "tag=${LATEST_TAG}" >> $GITHUB_OUTPUT if [ -n "$LATEST_TAG" ] && [ "$LATEST_TAG" != "vnull" ]; then
TAG="nightly-${LATEST_TAG}-${SHORTSHA}"
else
TAG="nightly-${DATE}-${SHORTSHA}"
fi
echo "tag=$TAG" >> "$GITHUB_OUTPUT"
echo "tags=nightly, $TAG" >> "$GITHUB_OUTPUT"
echo "Resolved nightly tags: nightly, $TAG"
- name: Set up QEMU - name: Set up QEMU
uses: docker/setup-qemu-action@v3 uses: docker/setup-qemu-action@v3
- name: Buildah Build - name: Build Container Image (multi-arch)
id: build-container id: build-container
uses: redhat-actions/buildah-build@v2 uses: redhat-actions/buildah-build@v2
with: with:
containerfiles: | containerfiles: |
./packages/web/infra/Containerfile ./packages/web/infra/Containerfile
image: ${{ github.event.repository.full_name }} image: ${{ env.REGISTRY_IMAGE }}
tags: nightly-${{ steps.get_release.outputs.tag }}-${{ github.sha }} tags: ${{ steps.meta.outputs.tags }}
oci: true oci: true
platforms: linux/amd64, linux/arm64 platforms: linux/amd64, linux/arm64
labels: |
org.opencontainers.image.source=${{ github.repository }}
org.opencontainers.image.revision=${{ github.sha }}
org.opencontainers.image.created=${{ github.run_id }}
- name: Push To Registry - name: Push To GHCR
id: push-to-registry id: push-to-registry
uses: redhat-actions/push-to-registry@v2 uses: redhat-actions/push-to-registry@v2
with: with:
@ -95,6 +105,5 @@ jobs:
username: ${{ github.actor }} username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }} password: ${{ secrets.GITHUB_TOKEN }}
- name: Print image url - name: Print image URL
run: echo "Image pushed to ${{ steps.push-to-registry.outputs.registry-paths }}" run: echo "Image pushed to ${{ steps.push-to-registry.outputs.registry-paths }}"

52
.github/workflows/pr.yml

@ -1,52 +1,52 @@
name: Pull Request CI name: Pull Request CI
on: pull_request on:
pull_request:
types: [opened, synchronize, reopened, ready_for_review]
permissions: permissions:
contents: write contents: read
packages: write
concurrency:
group: pr-${{ github.event.pull_request.number }}-ci
cancel-in-progress: true
env:
CI: true
jobs: jobs:
build-and-package: build-and-package:
runs-on: ubuntu-latest runs-on: ubuntu-latest
# Skip for draft PRs; remove this line if you want to run on drafts too
if: ${{ github.event.pull_request.draft == false }}
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 22
- name: Setup pnpm - name: Setup pnpm
uses: pnpm/action-setup@v4 uses: pnpm/action-setup@v4
with: with:
version: latest version: latest
- name: Install Dependencies - name: Setup Node.js
# Commands will run from 'packages/web' uses: actions/setup-node@v4
working-directory: packages/web
run: pnpm install
- name: Cache pnpm dependencies
uses: actions/cache@v4
with: with:
path: | node-version: 22
~/.pnpm-store cache: pnpm
packages/web/node_modules cache-dependency-path: '**/pnpm-lock.yaml'
key: ${{ runner.os }}-pnpm-${{ hashFiles('packages/web/pnpm-lock.yaml') }}
restore-keys: | - name: Install dependencies (root)
${{ runner.os }}-pnpm- run: pnpm install --frozen-lockfile
- name: Run linter - name: Run linter
run: pnpm run lint run: pnpm run lint
- name: Check formatter - name: Check formatter
run: pnpm run check run: pnpm run check
- name: Run tests - name: Run tests
run: pnpm run test run: pnpm run test
- name: Build Package - name: Build web package
working-directory: packages/web run: pnpm --filter "./packages/web" run build
run: pnpm run build

130
.github/workflows/release-packages.yml

@ -11,81 +11,103 @@ on:
jobs: jobs:
release: release:
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions:
contents: read
id-token: write # <-- required for JSR OIDC
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@v4
# --- Setup Node.js and pnpm --- # Node + pnpm (with cache)
- name: Setup Node.js - name: Setup Node
uses: actions/setup-node@v4 uses: actions/setup-node@v4
with: with:
node-version: 22 node-version: 22
cache: pnpm
cache-dependency-path: '**/pnpm-lock.yaml'
- name: Setup pnpm - name: Setup pnpm
uses: pnpm/action-setup@v4 uses: pnpm/action-setup@v4
with: with:
version: latest version: latest
# --- Setup Deno --- - name: Configure npm auth
- name: Setup Deno env:
uses: denoland/setup-deno@v2 NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
with: run: |
deno-version: v2.x pnpm config set //registry.npmjs.org/:_authToken=${NODE_AUTH_TOKEN}
pnpm config set registry https://registry.npmjs.org/
# --- Cache pnpm Dependencies ---
- name: Cache pnpm Dependencies
uses: actions/cache@v4
with:
path: |
~/.pnpm-store
packages/web/node_modules
key: ${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-
# --- Cache Deno Dependencies ---
- name: Cache Deno Dependencies
uses: actions/cache@v4
with:
path: ~/.cache/deno
key: ${{ runner.os }}-deno-${{ hashFiles('**/deno.lock') }}
restore-keys: |
${{ runner.os }}-deno-
- name: Configure pnpm registry
run: pnpm config set registry https://registry.npmjs.org/
- name: Configure pnpm auth - name: Install deps (root)
run: pnpm config set //registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }} run: pnpm install
- name: Publish packages to npm and JSR - name: Resolve package list
id: pkgs
shell: bash
run: |
if [ "${{ github.event.inputs.packages }}" = "all" ] || [ -z "${{ github.event.inputs.packages }}" ]; then
mapfile -t TARGETS < <(ls -d packages/* | grep -v 'packages/web')
else
IFS=',' read -ra TARGETS <<< "${{ github.event.inputs.packages }}"
TARGETS=("${TARGETS[@]/#/packages/}")
fi
printf '%s\n' "${TARGETS[@]}" | paste -sd, - > targets.txt
echo "list=$(cat targets.txt)" >> "$GITHUB_OUTPUT"
- name: Build selected packages (tsdown)
run: | run: |
for dir in packages/*; do IFS=',' read -ra TARGETS <<< "${{ steps.pkgs.outputs.list }}"
if [ "$dir" != "packages/web" ]; then for dir in "${TARGETS[@]}"; do
echo "Processing $dir" echo "Building $dir"
pnpm --filter "./$dir" run build
done
cd $dir - name: Sync jsr.json version from package.json
run: |
IFS=',' read -ra TARGETS <<< "${{ steps.pkgs.outputs.list }}"
for dir in "${TARGETS[@]}"; do
if [ -f "$dir/jsr.json" ] && [ -f "$dir/package.json" ]; then
PKG_VER=$(jq -r .version "$dir/package.json")
jq --arg v "$PKG_VER" '.version = $v' "$dir/jsr.json" > "$dir/jsr.json.tmp" && mv "$dir/jsr.json.tmp" "$dir/jsr.json"
echo "Updated $dir/jsr.json to version $PKG_VER"
fi
done
# Build and publish to npm if package.json exists - name: Publish to JSR (OIDC)
if [ -f "package.json" ]; then run: |
echo "Building and publishing $dir to npm..." set -euo pipefail
pnpm install IFS=',' read -ra TARGETS <<< "${{ steps.pkgs.outputs.list }}"
pnpm run build:npm for dir in "${TARGETS[@]}"; do
pnpm run publish:npm || echo "npm publish failed for $dir" if [ -f "$dir/jsr.json" ]; then
echo "Publishing $dir to JSR via OIDC…"
cd "$dir"
[ -d dist ] || pnpm run build
if ! npx --yes jsr publish 2>&1 | tee jsr_publish.log; then
echo "JSR publish failed for $dir. Error output:"
cat jsr_publish.log
fi fi
cd - >/dev/null
fi
done
pnpm run prepare:jsr - name: Replace exports entry in package.json
run: |
# Publish to JSR if jsr.json exists tmp=$(mktemp)
if [ -f "jsr.json" ]; then jq '.exports["."] = "./dist/mod.mjs"' package.json > "$tmp" \
echo "Publishing $dir to jsr..." && mv "$tmp" package.json
deno publish || echo "JSR publish failed for $dir"
fi
cd - > /dev/null - name: Publish to npm
else run: |
echo "Skipping $dir" set -euo pipefail
IFS=',' read -ra TARGETS <<< "${{ steps.pkgs.outputs.list }}"
for dir in "${TARGETS[@]}"; do
if [ -f "$dir/package.json" ]; then
echo "Publishing $dir to npm…"
cd "$dir"
[ -d dist ] || pnpm run build
npm publish --access public || echo "npm publish failed for $dir"
cd - >/dev/null
fi fi
done done

58
.github/workflows/release-web.yml

@ -10,7 +10,7 @@ on:
required: false required: false
default: "" default: ""
tag_name: tag_name:
description: "Tag to use for artifacts/images (defaults to adhoc-<sha>)" description: "Tag to use for artifacts/images (defaults to <sha>)"
required: false required: false
default: "" default: ""
attach_to_release: attach_to_release:
@ -36,53 +36,56 @@ jobs:
# For manual runs, allow building a chosen ref (branch/tag/SHA) # For manual runs, allow building a chosen ref (branch/tag/SHA)
ref: ${{ inputs.ref != '' && inputs.ref || github.ref }} ref: ${{ inputs.ref != '' && inputs.ref || github.ref }}
- name: Determine tag for this run - name: Determine tag & latest flag
id: meta id: meta
shell: bash
run: | run: |
# tag from release event, or user input, or fallback to adhoc-<shortsha> # Determine TAG
if [ "${{ github.event_name }}" = "release" ]; then if [ "${{ github.event_name }}" = "release" ]; then
TAG="${{ github.event.release.tag_name }}" TAG="${{ github.event.release.tag_name }}"
# Push "latest" only for full releases (not prereleases)
if [ "${{ github.event.release.prerelease }}" = "true" ]; then
PUSH_LATEST="false"
else
PUSH_LATEST="true"
fi
elif [ -n "${{ inputs.tag_name }}" ]; then elif [ -n "${{ inputs.tag_name }}" ]; then
TAG="${{ inputs.tag_name }}" TAG="${{ inputs.tag_name }}"
PUSH_LATEST="false"
else else
SHA="$(git rev-parse --short=12 HEAD)" SHA="$(git rev-parse --short=12 HEAD)"
TAG="adhoc-${SHA}" TAG="adhoc-${SHA}"
PUSH_LATEST="false"
fi fi
echo "tag=$TAG" >> "$GITHUB_OUTPUT" echo "tag=$TAG" >> "$GITHUB_OUTPUT"
echo "Resolved tag: $TAG" echo "push_latest=$PUSH_LATEST" >> "$GITHUB_OUTPUT"
echo "Resolved tag: $TAG (push_latest=$PUSH_LATEST)"
# --- Setup Node.js and pnpm --- # --- Setup Node.js and pnpm (with cache) ---
- name: Setup Node.js - name: Setup Node.js
uses: actions/setup-node@v4 uses: actions/setup-node@v4
with: with:
node-version: 22 node-version: 22
cache: pnpm
cache-dependency-path: '**/pnpm-lock.yaml'
- name: Setup pnpm - name: Setup pnpm
uses: pnpm/action-setup@v4 uses: pnpm/action-setup@v4
with: with:
version: latest version: latest
# --- Cache pnpm Dependencies ---
- name: Cache pnpm Dependencies
uses: actions/cache@v4
with:
path: |
~/.pnpm-store
packages/web/node_modules
key: ${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-
- name: Install dependencies - name: Install dependencies
run: pnpm install --frozen-lockfile run: pnpm install --frozen-lockfile
- name: Create Web App Release Archive - name: Create Web App Release Archive
run: pnpm --filter "meshtastic-web" run package working-directory: packages/web
run: pnpm run package
- name: Upload Web App Archive (artifact) - name: Upload Web App Archive (artifact)
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
with: with:
name: web-build name: web-build-${{ steps.meta.outputs.tag }}
if-no-files-found: error if-no-files-found: error
path: packages/web/dist/build.tar path: packages/web/dist/build.tar
@ -90,6 +93,7 @@ jobs:
if: ${{ github.event_name == 'release' || inputs.attach_to_release == true }} if: ${{ github.event_name == 'release' || inputs.attach_to_release == true }}
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
shell: bash
run: | run: |
if [ "${{ github.event_name }}" = "release" ]; then if [ "${{ github.event_name }}" = "release" ]; then
TAG="${{ steps.meta.outputs.tag }}" TAG="${{ steps.meta.outputs.tag }}"
@ -105,6 +109,22 @@ jobs:
- name: Set up QEMU - name: Set up QEMU
uses: docker/setup-qemu-action@v3 uses: docker/setup-qemu-action@v3
- name: Compute image tags
id: tags
shell: bash
run: |
if [ "${{ steps.meta.outputs.push_latest }}" = "true" ]; then
echo "list=latest, ${{ steps.meta.outputs.tag }}" >> "$GITHUB_OUTPUT"
else
echo "list=${{ steps.meta.outputs.tag }}" >> "$GITHUB_OUTPUT"
fi
TAGS="latest, ${{ steps.meta.outputs.tag }}"
else
TAGS="${{ steps.meta.outputs.tag }}"
fi
echo "list=$TAGS" >> "$GITHUB_OUTPUT"
echo "Using image tags: $TAGS"
- name: Build Container Image - name: Build Container Image
id: build-container id: build-container
uses: redhat-actions/buildah-build@v2 uses: redhat-actions/buildah-build@v2
@ -112,7 +132,7 @@ jobs:
containerfiles: | containerfiles: |
./packages/web/infra/Containerfile ./packages/web/infra/Containerfile
image: ${{ env.REGISTRY_IMAGE }} image: ${{ env.REGISTRY_IMAGE }}
tags: latest, ${{ steps.meta.outputs.tag }} tags: ${{ steps.tags.outputs.list }}
oci: true oci: true
platforms: linux/amd64, linux/arm64 platforms: linux/amd64, linux/arm64

63
.github/workflows/update-stable-from-master.yml

@ -7,44 +7,67 @@ on:
permissions: permissions:
contents: write contents: write
concurrency:
group: update-stable-${{ github.run_id }}
cancel-in-progress: true
jobs: jobs:
update-stable-branch: update-stable-branch:
name: Update Stable Branch from Main name: Update stable from latest release source
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v4 uses: actions/checkout@v4
with: with:
fetch-depth: 0 fetch-depth: 0 # need full history for reset/push
token: ${{ secrets.GITHUB_TOKEN }}
- name: Configure Git - name: Configure Git author
run: | run: |
git config user.name "GitHub Actions Bot" git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com" git config user.email "github-actions[bot]@users.noreply.github.com"
- name: Fetch latest main and stable branches - name: Determine source ref & SHA
id: meta
shell: bash
run: | run: |
git fetch origin main:main set -euo pipefail
git fetch origin stable:stable || echo "Stable branch not found remotely, will create." SRC="${{ github.event.release.target_commitish }}"
if [ -z "$SRC" ] || ! git ls-remote --exit-code origin "refs/heads/$SRC" >/dev/null 2>&1; then
# Fallback to main if target_commitish is empty or not a branch
SRC="main"
fi
- name: Get latest main commit SHA echo "Using source branch: $SRC"
id: get_main_sha git fetch origin "$SRC":"refs/remotes/origin/$SRC" --prune
run: echo "MAIN_SHA=$(git rev-parse main)" >> $GITHUB_ENV SHA="$(git rev-parse "origin/$SRC")"
echo "sha=$SHA" >> "$GITHUB_OUTPUT"
echo "src=$SRC" >> "$GITHUB_OUTPUT"
- name: Check out stable branch - name: Prepare local stable branch
shell: bash
run: | run: |
set -euo pipefail
# Ensure we have the remote stable ref if it exists
git fetch origin stable:refs/remotes/origin/stable || true
if git show-ref --verify --quiet refs/heads/stable; then if git show-ref --verify --quiet refs/heads/stable; then
git checkout stable echo "Local stable exists."
git pull origin stable # Sync with remote stable if it exists elif git show-ref --verify --quiet refs/remotes/origin/stable; then
echo "Creating local stable tracking branch from remote."
git checkout -b stable --track origin/stable
else else
echo "Creating local stable branch based on main HEAD." echo "Creating new local stable branch at source SHA."
git checkout -b stable ${{ env.MAIN_SHA }} git checkout -b stable "${{ steps.meta.outputs.sha }}"
fi fi
- name: Reset stable branch to latest main - name: Reset stable to source SHA
run: git reset --hard ${{ env.MAIN_SHA }} run: |
git checkout stable
git reset --hard "${{ steps.meta.outputs.sha }}"
git status --short --branch
- name: Force push stable branch - name: Push stable (force-with-lease)
run: git push origin stable --force run: |
# Safer than --force; refuses if remote moved unexpectedly
git push origin stable --force-with-lease

1
.gitignore

@ -8,3 +8,4 @@ __screenshots__*
*.diff *.diff
npm/ npm/
.idea .idea
**/LICENSE

14
package.json

@ -1,5 +1,5 @@
{ {
"name": "meshtastic-web", "name": "@meshtastic/web",
"version": "2.7.0-0", "version": "2.7.0-0",
"type": "module", "type": "module",
"description": "Meshtastic web client monorepo", "description": "Meshtastic web client monorepo",
@ -25,7 +25,7 @@
"check:fix": "biome check --write", "check:fix": "biome check --write",
"build:all": "pnpm run --filter '*' build", "build:all": "pnpm run --filter '*' build",
"clean:all": "pnpm run --filter '*' clean", "clean:all": "pnpm run --filter '*' clean",
"publish:packages": "pnpm run --filter 'packages/transport-* packages/core' build", "publish:packages": "pnpm run build --filter 'packages/transport-*'",
"test": "vitest" "test": "vitest"
}, },
"dependencies": { "dependencies": {
@ -39,6 +39,14 @@
"biome": "^0.3.3", "biome": "^0.3.3",
"tsdown": "^0.13.4", "tsdown": "^0.13.4",
"typescript": "^5.8.3", "typescript": "^5.8.3",
"vitest": "^3.2.4" "vitest": "^3.2.4"
},
"pnpm": {
"onlyBuiltDependencies": [
"@tailwindcss/oxide",
"core-js",
"esbuild",
"simple-git-hooks"
]
} }
} }

11
packages/core/package.json

@ -1,10 +1,11 @@
{ {
"name": "@meshtastic/core", "name": "@meshtastic/core",
"version": "2.6.6", "version": "2.6.6-1",
"description": "Core functionalities for Meshtastic web applications.", "description": "Core functionalities for Meshtastic web applications.",
"exports": { "exports": {
".": "./mod.ts" ".": "./mod.ts"
}, },
"type": "module",
"main": "./dist/mod.mjs", "main": "./dist/mod.mjs",
"module": "./dist/mod.mjs", "module": "./dist/mod.mjs",
"types": "./dist/mod.d.mts", "types": "./dist/mod.d.mts",
@ -16,12 +17,18 @@
"splitting": false, "splitting": false,
"clean": true "clean": true
}, },
"files": [
"package.json",
"README.md",
"LICENSE",
"dist"
],
"scripts": { "scripts": {
"preinstall": "npx only-allow pnpm", "preinstall": "npx only-allow pnpm",
"prepack": "cp ../../LICENSE ./LICENSE", "prepack": "cp ../../LICENSE ./LICENSE",
"clean": "rm -rf dist LICENSE", "clean": "rm -rf dist LICENSE",
"build:npm": "tsdown", "build:npm": "tsdown",
"publish:npm": "pnpm clean && pnpm build:npm && pnpm publish --access public", "publish:npm": "pnpm clean && pnpm build:npm && pnpm publish --access public --no-git-checks",
"prepare:jsr": "rm -rf dist && pnpm dlx pkg-to-jsr", "prepare:jsr": "rm -rf dist && pnpm dlx pkg-to-jsr",
"publish:jsr": "pnpm run prepack && pnpm prepare:jsr && deno publish --allow-dirty --no-check" "publish:jsr": "pnpm run prepack && pnpm prepare:jsr && deno publish --allow-dirty --no-check"
}, },

7
packages/transport-deno/package.json

@ -8,7 +8,6 @@
"main": "./dist/mod.mjs", "main": "./dist/mod.mjs",
"module": "./dist/mod.mjs", "module": "./dist/mod.mjs",
"types": "./dist/mod.d.mts", "types": "./dist/mod.d.mts",
"files": ["dist/*", "mod.ts", "README.md", "../../LICENSE"],
"license": "GPL-3.0-only", "license": "GPL-3.0-only",
"tsdown": { "tsdown": {
"entry": "mod.ts", "entry": "mod.ts",
@ -17,6 +16,12 @@
"splitting": false, "splitting": false,
"clean": true "clean": true
}, },
"files": [
"package.json",
"README.md",
"LICENSE",
"dist"
],
"scripts": { "scripts": {
"preinstall": "npx only-allow pnpm", "preinstall": "npx only-allow pnpm",
"prepack": "cp ../../LICENSE ./LICENSE", "prepack": "cp ../../LICENSE ./LICENSE",

18
packages/transport-http/package.json

@ -1,8 +1,15 @@
{ {
"name": "@meshtastic/transport-http", "name": "@meshtastic/transport-http",
"version": "0.2.3", "version": "0.2.3-2",
"description": "A transport layer for Meshtastic applications using HTTP.", "description": "A transport layer for Meshtastic applications using HTTP.",
"exports": {".": "./mod.ts"}, "exports": {".": "./mod.ts"},
"type": "module",
"files": [
"package.json",
"README.md",
"LICENSE",
"dist"
],
"main": "./dist/mod.mjs", "main": "./dist/mod.mjs",
"module": "./dist/mod.mjs", "module": "./dist/mod.mjs",
"types": "./dist/mod.d.mts", "types": "./dist/mod.d.mts",
@ -14,18 +21,13 @@
"splitting": false, "splitting": false,
"clean": true "clean": true
}, },
"files": [
"package.json",
"README.md",
"LICENSE",
"dist"
],
"scripts": { "scripts": {
"preinstall": "npx only-allow pnpm", "preinstall": "npx only-allow pnpm",
"prepack": "cp ../../LICENSE ./LICENSE", "prepack": "cp ../../LICENSE ./LICENSE",
"clean": "rm -rf dist LICENSE", "clean": "rm -rf dist LICENSE",
"build:npm": "tsdown", "build:npm": "tsdown",
"publish:npm": "pnpm clean && pnpm build:npm && pnpm publish --access public",
"publish:npm": "pnpm clean && pnpm build:npm && pnpm publish --access public --no-git-checks",
"prepare:jsr": "rm -rf dist && pnpm dlx pkg-to-jsr", "prepare:jsr": "rm -rf dist && pnpm dlx pkg-to-jsr",
"publish:jsr": "pnpm run prepack && pnpm prepare:jsr && deno publish --allow-dirty --no-check" "publish:jsr": "pnpm run prepack && pnpm prepare:jsr && deno publish --allow-dirty --no-check"
}, },

28
packages/transport-node-serial/README.md

@ -0,0 +1,28 @@
# @meshtastic/transport-node-serial
[![JSR](https://jsr.io/badges/@meshtastic/transport-node-serial)](https://jsr.io/@meshtastic/transport-node-serial)
[![CI](https://img.shields.io/github/actions/workflow/status/meshtastic/js/ci.yml?branch=master&label=actions&logo=github&color=yellow)](https://github.com/meshtastic/js/actions/workflows/ci.yml)
[![CLA assistant](https://cla-assistant.io/readme/badge/meshtastic/meshtastic.js)](https://cla-assistant.io/meshtastic/meshtastic.js)
[![Fiscal Contributors](https://opencollective.com/meshtastic/tiers/badge.svg?label=Fiscal%20Contributors&color=deeppink)](https://opencollective.com/meshtastic/)
[![Vercel](https://img.shields.io/static/v1?label=Powered%20by&message=Vercel&style=flat&logo=vercel&color=000000)](https://vercel.com?utm_source=meshtastic&utm_campaign=oss)
## Overview
`@meshtastic/transport-noden-node` Provides Serial transport (Node) for Meshtastic
devices. Installation instructions are available at
[JSR](https://jsr.io/@meshtastic/transport-node-serial)
[NPM](https://www.npmjs.com/package/@meshtastic/transport-node-serial)
## Usage
```ts
import { MeshDevice } from "@meshtastic/core";
import { TransportNodeSerial } from "@meshtastic/transport-node-serial";
const transport = await TransportNodeSerial.create("/dev/cu.usbserial-0001");
const device = new MeshDevice(transport);
```
## Stats
![Alt](https://repobeats.axiom.co/api/embed/5330641586e92a2ec84676fedb98f6d4a7b25d69.svg "Repobeats analytics image")

1
packages/transport-node-serial/mod.ts

@ -0,0 +1 @@
export { TransportNodeSerial } from "./src/transport.ts";

39
packages/transport-node-serial/package.json

@ -0,0 +1,39 @@
{
"name": "@meshtastic/transport-node-serial",
"version": "0.0.1",
"description": "NodeJS-specific serial transport layer for Meshtastic web applications.",
"exports": {
".": "./dist/mod.mjs"
},
"main": "./dist/mod.mjs",
"module": "./dist/mod.mjs",
"types": "./dist/mod.d.mts",
"license": "GPL-3.0-only",
"tsdown": {
"entry": "mod.ts",
"dts": true,
"format": ["esm"],
"splitting": false,
"clean": true
},
"files": [
"package.json",
"README.md",
"LICENSE",
"dist"
],
"scripts": {
"preinstall": "npx only-allow pnpm",
"prepack": "cp ../../LICENSE ./LICENSE",
"clean": "rm -rf dist LICENSE",
"build:npm": "tsdown",
"publish:npm": "pnpm clean && pnpm build:npm && pnpm publish --access public",
"prepare:jsr": "rm -rf dist && pnpm dlx pkg-to-jsr",
"publish:jsr": "pnpm run prepack && pnpm prepare:jsr && deno publish --allow-dirty --no-check"
},
"dependencies": {
"@meshtastic/core": "workspace:*",
"serialport": "^13.0.0"
}
}

87
packages/transport-node-serial/src/transport.ts

@ -0,0 +1,87 @@
import { Readable, Writable } from "node:stream";
import type { Types } from "@meshtastic/core";
import { Utils } from "@meshtastic/core";
import { SerialPort } from "serialport";
export class TransportNodeSerial implements Types.Transport {
private readonly _toDevice: WritableStream<Uint8Array>;
private readonly _fromDevice: ReadableStream<Types.DeviceOutput>;
private port: SerialPort | undefined;
/**
* Creates and connects a new TransportNode instance.
* @param path - Path to the serial device
* @param baudRate - The port number for the TCP connection (defaults to 4403).
* @returns A promise that resolves with a connected TransportNode instance.
*/
public static create(path: string, baudRate = 115200): Promise<TransportNodeSerial> {
return new Promise((resolve, reject) => {
const port = new SerialPort({
path,
baudRate,
autoOpen: true,
});
const onError = (err: Error) => {
port.close();
reject(err);
};
port.once("error", onError);
port.on("open", () => {
port.removeListener("error", onError);
resolve(new TransportNodeSerial(port));
});
});
}
/**
* Constructs a new TransportNode.
* @param port - An active Node.js SerialPort connection.
*/
constructor(port: SerialPort) {
this.port = port;
this.port.on("error", (err) => {
console.error("Serial port connection error:", err);
});
const fromDeviceSource = Readable.toWeb(
port,
) as ReadableStream<Uint8Array>;
this._fromDevice = fromDeviceSource.pipeThrough(Utils.fromDeviceStream());
// Stream for data going FROM the application TO the Meshtastic device.
const toDeviceTransform = Utils.toDeviceStream;
this._toDevice = toDeviceTransform.writable;
// The readable end of the transform is then piped to the Node.js SerialPort connection.
// A similar assertion is needed here because `Writable.toWeb` also returns
// a generically typed stream (`WritableStream<any>`).
toDeviceTransform.readable
.pipeTo(Writable.toWeb(port) as WritableStream<Uint8Array>)
.catch((err) => {
console.error("Error piping data to serial port:", err);
this.port.close(err as Error);
});
}
/**
* The WritableStream to send data to the Meshtastic device.
*/
public get toDevice(): WritableStream<Uint8Array> {
return this._toDevice;
}
/**
* The ReadableStream to receive data from the Meshtastic device.
*/
public get fromDevice(): ReadableStream<Types.DeviceOutput> {
return this._fromDevice;
}
disconnect() {
this.port.close();
this.port = undefined;
return Promise.resolve();
}
}

18
packages/transport-node-serial/tsconfig.json

@ -0,0 +1,18 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"module": "ESNext",
"target": "ES2020",
"declaration": true,
"outDir": "./dist",
"moduleResolution": "bundler",
"emitDeclarationOnly": false,
"esModuleInterop": true,
},
"include": ["src"]
}

5
packages/transport-node/package.json

@ -1,10 +1,11 @@
{ {
"name": "@meshtastic/transport-node", "name": "@meshtastic/transport-node",
"version": "0.0.1", "version": "0.0.1-1",
"description": "NodeJS-specific transport layer for Meshtastic web applications.", "description": "NodeJS-specific transport layer for Meshtastic web applications.",
"exports": { "exports": {
".": "./mod.ts" ".": "./mod.ts"
}, },
"type": "module",
"main": "./dist/mod.mjs", "main": "./dist/mod.mjs",
"module": "./dist/mod.mjs", "module": "./dist/mod.mjs",
"types": "./dist/mod.d.mts", "types": "./dist/mod.d.mts",
@ -28,7 +29,7 @@
"prepack": "cp ../../LICENSE ./LICENSE", "prepack": "cp ../../LICENSE ./LICENSE",
"clean": "rm -rf dist LICENSE", "clean": "rm -rf dist LICENSE",
"build:npm": "tsdown", "build:npm": "tsdown",
"publish:npm": "pnpm clean && pnpm build:npm && pnpm publish --access public", "publish:npm": "pnpm clean && pnpm build:npm && pnpm publish --access public --no-git-checks",
"prepare:jsr": "rm -rf dist && pnpm dlx pkg-to-jsr", "prepare:jsr": "rm -rf dist && pnpm dlx pkg-to-jsr",
"publish:jsr": "pnpm run prepack && pnpm prepare:jsr && deno publish --allow-dirty --no-check" "publish:jsr": "pnpm run prepack && pnpm prepare:jsr && deno publish --allow-dirty --no-check"
}, },

12
packages/transport-web-bluetooth/package.json

@ -1,14 +1,20 @@
{ {
"name": "@meshtastic/transport-web-bluetooth", "name": "@meshtastic/transport-web-bluetooth",
"version": "0.1.4", "version": "0.1.4-1",
"description": "A transport layer for Meshtastic applications using Web Bluetooth.", "description": "A transport layer for Meshtastic applications using Web Bluetooth.",
"exports": { "exports": {
".": "./mod.ts" ".": "./mod.ts"
}, },
"type": "module",
"main": "./dist/mod.mjs", "main": "./dist/mod.mjs",
"module": "./dist/mod.mjs", "module": "./dist/mod.mjs",
"types": "./dist/mod.d.mts", "types": "./dist/mod.d.mts",
"files": ["dist/*", "mod.ts", "README.md", "../../LICENSE"], "files": [
"package.json",
"README.md",
"LICENSE",
"dist"
],
"license": "GPL-3.0-only", "license": "GPL-3.0-only",
"tsdown": { "tsdown": {
"entry": "mod.ts", "entry": "mod.ts",
@ -22,7 +28,7 @@
"prepack": "cp ../../LICENSE ./LICENSE", "prepack": "cp ../../LICENSE ./LICENSE",
"clean": "rm -rf dist LICENSE", "clean": "rm -rf dist LICENSE",
"build:npm": "tsdown", "build:npm": "tsdown",
"publish:npm": "pnpm clean && pnpm build:npm && pnpm publish --access public", "publish:npm": "pnpm clean && pnpm build:npm && pnpm publish --access public --no-git-checks",
"prepare:jsr": "rm -rf dist && pnpm dlx pkg-to-jsr", "prepare:jsr": "rm -rf dist && pnpm dlx pkg-to-jsr",
"publish:jsr": "pnpm run prepack && pnpm prepare:jsr && deno publish --allow-dirty --no-check" "publish:jsr": "pnpm run prepack && pnpm prepare:jsr && deno publish --allow-dirty --no-check"
}, },

12
packages/transport-web-serial/package.json

@ -1,14 +1,20 @@
{ {
"name": "@meshtastic/transport-web-serial", "name": "@meshtastic/transport-web-serial",
"version": "0.2.3", "version": "0.2.3-1",
"description": "A transport layer for Meshtastic applications using Web Serial API.", "description": "A transport layer for Meshtastic applications using Web Serial API.",
"exports": { "exports": {
".": "./mod.ts" ".": "./mod.ts"
}, },
"type": "module",
"main": "./dist/mod.mjs", "main": "./dist/mod.mjs",
"module": "./dist/mod.mjs", "module": "./dist/mod.mjs",
"types": "./dist/mod.d.mts", "types": "./dist/mod.d.mts",
"files": ["dist/*", "mod.ts", "README.md", "../../LICENSE"], "files": [
"package.json",
"README.md",
"LICENSE",
"dist"
],
"license": "GPL-3.0-only", "license": "GPL-3.0-only",
"tsdown": { "tsdown": {
"entry": "mod.ts", "entry": "mod.ts",
@ -22,7 +28,7 @@
"prepack": "cp ../../LICENSE ./LICENSE", "prepack": "cp ../../LICENSE ./LICENSE",
"clean": "rm -rf dist LICENSE", "clean": "rm -rf dist LICENSE",
"build:npm": "tsdown", "build:npm": "tsdown",
"publish:npm": "pnpm clean && pnpm build:npm && pnpm publish --access public", "publish:npm": "pnpm clean && pnpm build:npm && pnpm publish --access public --no-git-checks",
"prepare:jsr": "rm -rf dist && pnpm dlx pkg-to-jsr", "prepare:jsr": "rm -rf dist && pnpm dlx pkg-to-jsr",
"publish:jsr": "pnpm run prepack && pnpm prepare:jsr && deno publish --allow-dirty --no-check" "publish:jsr": "pnpm run prepack && pnpm prepare:jsr && deno publish --allow-dirty --no-check"
}, },

150
packages/web/CONTRIBUTIONS.md

@ -0,0 +1,150 @@
# Contributing to Meshtastic Web
Thank you for your interest in contributing to **Meshtastic Web**! 🎉
We welcome all contributions—whether it’s fixing a typo, improving documentation, adding new features, or reporting bugs. This document outlines how to get started and the conventions we follow.
---
## 📋 Code of Conduct
We follow the [Meshtastic Code of Conduct](https://meshtastic.org/docs/legal/conduct/).
Please make sure you are familiar with it before contributing.
---
## 🚀 Getting Started
Before making changes, please take some time to explore the repository and its monorepo structure.
Understanding how the packages are organized will make it much easier to contribute effectively.
[Meshtastic Web](https://github.com/meshtastic/web/)
### Prerequisites
- [Node.js](https://nodejs.org/) (v22 or later)
- [pnpm](https://pnpm.io/) (v10.14.x or later)
- Git
### Installation
Clone the repo and install dependencies:
```bash
git clone https://github.com/meshtastic/web.git meshtastic-web
cd meshtastic-web
pnpm install
```
### Development
Start the development server:
```bash
pnpm --filter @meshtastic/web dev
```
Once running, the site will be available at:
👉 **http://localhost:3000**
---
## 🗂 Repository Structure
Meshtastic Web uses a **monorepo** setup managed with **pnpm workspaces**:
```
/packages
├─ web # React frontend
├─ core # Shared types & logic
├─ transport-* # Transport layer packages
└─ ...other packages
```
---
## ✅ Contribution Workflow
1. **Fork the repo** and create your branch from `main`.
### Branch Naming
- Use [Conventional Commit](https://www.conventionalcommits.org/) style for your branch names:
```
feat/add-project-filter
fix/storage-service
chore/update-ci-cache
```
2. **Make your changes locally** and verify that the app runs as expected at `http://localhost:3000`.
3. **Commit your changes** with a descriptive commit message that follows the [Conventional Commits](https://www.conventionalcommits.org/) style.
4. **Open a Pull Request (PR)** from your fork's branch to the main repository's `main` branch on GitHub:
- Clearly describe the problem and solution.
- Reference related issues (e.g., `Fixes #123`).
- Keep PRs focused on a single feature or fix.
- Complete all fields in the PR template.
- Tag a **Meshtastic Web developer** in the PR for review.
5. **CI/CD**:
- Our GitHub Actions workflows handle builds, linting, and packaging automatically.
- All checks must pass before merge.
---
## 🌍 Internationalization (i18n)
Meshtastic Web supports multiple languages. If your changes introduce **new user-facing strings**:
- Add them to the **`en.json`** file.
- Do **not** hardcode English strings directly in components.
- This ensures they can be translated into other languages.
🔗 See these guides for more details:
- [i18n Developer Guide](https://github.com/meshtastic/web/blob/main/packages/web/CONTRIBUTING_I18N_DEVELOPER_GUIDE.md)
- [Translation Contribution Guide](https://github.com/meshtastic/web/blob/main/packages/web/CONTRIBUTING_TRANSLATIONS.md)
---
## 🧪 Testing
Tests are written with [Vitest](https://vitest.dev/).
Run all tests locally with:
```bash
pnpm --filter @meshtastic/web test
```
Please include tests for new features and bug fixes whenever possible.
---
## 📝 Commit Messages
We use **Conventional Commits**:
- `feat:` – a new feature
- `fix:` – a bug fix
- `docs:` – documentation changes
- `chore:` – maintenance, dependencies, build scripts
- `refactor:` – code restructuring without feature changes
- `test:` – adding or updating tests
- `ci:` – CI/CD changes
Example:
```
feat: add toast notification system
fix: correct caching issue in storage service
```
---
## 💡 Tips for Contributors
- Keep PRs **small, focused, and atomic**.
- Discuss larger changes with the team on [Discord](https://discord.gg/meshtastic) before starting work.
- If unsure, open a draft PR for early feedback.
---
## 🙌 Community
Contributors are the heart of Meshtastic ❤️.
Join the conversation:
- [Discord](https://discord.gg/meshtastic)
- [GitHub Discussions](https://github.com/meshtastic/web/discussions)
---
## 📜 License
By contributing, you agree that your contributions will be licensed under the [GPL-3.0-only License](../../LICENSE).

89
packages/web/infra/default.conf

@ -1,42 +1,51 @@
server { server {
listen 8080; listen 8080;
server_name localhost; server_name localhost;
root /usr/share/nginx/html; root /usr/share/nginx/html;
index index.html index.htm; index index.html;
location / { location ~* \.(?:js|jsx|mjs|ts|tsx|css|png|jpg|jpeg|gif|ico|webp|avif|svg|ttf|otf|woff|woff2|map)$ {
try_files $uri $uri/ /index.html; access_log off;
} etag on;
error_page 500 502 503 504 /50x.html; expires 3M;
location = /50x.html { add_header Cache-Control "public, immutable";
internal; try_files $uri =404;
} }
location ~ /\.ht { location = /index.html {
deny all; etag on;
} add_header Cache-Control "no-cache";
}
gzip on;
gzip_disable "msie6"; location / {
try_files $uri $uri/ /index.html;
gzip_vary on; }
gzip_proxied any;
gzip_comp_level 6; error_page 500 502 503 504 /50x.html;
gzip_buffers 16 8k; location = /50x.html { internal; }
gzip_http_version 1.1;
gzip_types location ~ /\.ht { deny all; }
text/plain
text/css gzip on;
text/xml gzip_disable "msie6";
text/javascript gzip_vary on;
application/javascript gzip_proxied any;
application/x-javascript gzip_comp_level 6;
application/json gzip_buffers 16 8k;
application/xml gzip_http_version 1.1;
application/xml+rss gzip_types
font/ttf text/plain
font/otf text/css
image/svg+xml; text/xml
text/javascript
application/javascript
application/x-javascript
application/json
application/xml
application/xml+rss
font/ttf
font/otf
image/svg+xml;
} }

1
packages/web/package.json

@ -22,6 +22,7 @@
"test": "vitest", "test": "vitest",
"ts:check": "bun run tsc --noEmit", "ts:check": "bun run tsc --noEmit",
"preview": "vite preview", "preview": "vite preview",
"docker:build": "docker build -t meshtastic-web:latest -f ./infra/Containerfile .",
"generate:routes": "bun @tanstack/router-cli generate --outDir src/ routes --rootRoutePath /", "generate:routes": "bun @tanstack/router-cli generate --outDir src/ routes --rootRoutePath /",
"package": "gzipper c -i html,js,css,png,ico,svg,json,webmanifest,txt dist dist/output && tar -cvf dist/build.tar -C ./dist/output/ ." "package": "gzipper c -i html,js,css,png,ico,svg,json,webmanifest,txt dist dist/output && tar -cvf dist/build.tar -C ./dist/output/ ."
}, },

2
packages/web/public/i18n/locales/bg-BG/common.json

@ -25,7 +25,7 @@
"save": "Запис", "save": "Запис",
"scanQr": "Сканиране на QR кода", "scanQr": "Сканиране на QR кода",
"traceRoute": "Trace Route", "traceRoute": "Trace Route",
"submit": "Submit" "submit": "Изпращане"
}, },
"app": { "app": {
"title": "Meshtastic", "title": "Meshtastic",

24
packages/web/public/i18n/locales/bg-BG/deviceConfig.json

@ -18,22 +18,22 @@
"description": "Настройки за устройството", "description": "Настройки за устройството",
"buttonPin": { "buttonPin": {
"description": "Button pin override", "description": "Button pin override",
"label": "Button Pin" "label": "Пин за бутон"
}, },
"buzzerPin": { "buzzerPin": {
"description": "Buzzer pin override", "description": "Buzzer pin override",
"label": "Buzzer Pin" "label": "Пин за зумер"
}, },
"disableTripleClick": { "disableTripleClick": {
"description": "Disable triple click", "description": "Дезактивиране на трикратното щракване",
"label": "Disable Triple Click" "label": "Дезактивиране на трикратното щракване"
}, },
"doubleTapAsButtonPress": { "doubleTapAsButtonPress": {
"description": "Treat double tap as button press", "description": "Treat double tap as button press",
"label": "Double Tap as Button Press" "label": "Double Tap as Button Press"
}, },
"ledHeartbeatDisabled": { "ledHeartbeatDisabled": {
"description": "Disable default blinking LED", "description": "Дезактивиране на мигащия светодиод по подразбиране",
"label": "LED Heartbeat Disabled" "label": "LED Heartbeat Disabled"
}, },
"nodeInfoBroadcastInterval": { "nodeInfoBroadcastInterval": {
@ -138,7 +138,7 @@
"label": "Отместване на честотата" "label": "Отместване на честотата"
}, },
"frequencySlot": { "frequencySlot": {
"description": "LoRa frequency channel number", "description": "Номер на LoRa честотен канал",
"label": "Честотен слот" "label": "Честотен слот"
}, },
"hopLimit": { "hopLimit": {
@ -277,7 +277,7 @@
}, },
"enablePin": { "enablePin": {
"description": "GPS module enable pin override", "description": "GPS module enable pin override",
"label": "Enable Pin" "label": "Активиране на пин"
}, },
"fixedPosition": { "fixedPosition": {
"description": "Don't report GPS position, but a manually-specified one", "description": "Don't report GPS position, but a manually-specified one",
@ -341,7 +341,7 @@
}, },
"ina219Address": { "ina219Address": {
"description": "Address of the INA219 battery monitor", "description": "Address of the INA219 battery monitor",
"label": "INA219 Address" "label": "INA219 адрес"
}, },
"lightSleepDuration": { "lightSleepDuration": {
"description": "How long the device will be in light sleep for", "description": "How long the device will be in light sleep for",
@ -353,7 +353,7 @@
}, },
"noConnectionBluetoothDisabled": { "noConnectionBluetoothDisabled": {
"description": "If the device does not receive a Bluetooth connection, the BLE radio will be disabled after this long", "description": "If the device does not receive a Bluetooth connection, the BLE radio will be disabled after this long",
"label": "No Connection Bluetooth Disabled" "label": "Няма връзка Bluetooth е дезактивиран"
}, },
"powerSavingEnabled": { "powerSavingEnabled": {
"description": "Select if powered from a low-current source (i.e. solar), to minimize power consumption as much as possible.", "description": "Select if powered from a low-current source (i.e. solar), to minimize power consumption as much as possible.",
@ -390,10 +390,10 @@
}, },
"managed": { "managed": {
"description": "If enabled, device configuration options are only able to be changed remotely by a Remote Admin node via admin messages. Do not enable this option unless at least one suitable Remote Admin node has been setup, and the public key is stored in one of the fields above.", "description": "If enabled, device configuration options are only able to be changed remotely by a Remote Admin node via admin messages. Do not enable this option unless at least one suitable Remote Admin node has been setup, and the public key is stored in one of the fields above.",
"label": "Managed" "label": "Управляван"
}, },
"privateKey": { "privateKey": {
"description": "Used to create a shared key with a remote device", "description": "Използва се за създаване на споделен ключ с отдалечено устройство",
"label": "Частен ключ" "label": "Частен ключ"
}, },
"publicKey": { "publicKey": {
@ -418,7 +418,7 @@
}, },
"adminSettings": { "adminSettings": {
"description": "Настройки за Admin", "description": "Настройки за Admin",
"label": "Admin Settings" "label": "Администраторски настройки"
}, },
"loggingSettings": { "loggingSettings": {
"description": "Settings for Logging", "description": "Settings for Logging",

20
packages/web/public/i18n/locales/bg-BG/dialog.json

@ -9,10 +9,10 @@
"shortName": "Кратко име", "shortName": "Кратко име",
"title": "Промяна на името на устройството", "title": "Промяна на името на устройството",
"validation": { "validation": {
"longNameMax": "Long name must not be more than 40 characters", "longNameMax": "Дългото име не трябва да е повече от 40 знака",
"shortNameMax": "Short name must not be more than 4 characters", "shortNameMax": "Краткото име не трябва да е повече от 4 знака",
"longNameMin": "Long name must have at least 1 character", "longNameMin": "Дългото име трябва да съдържа поне 1 символ",
"shortNameMin": "Short name must have at least 1 character" "shortNameMin": "Краткото име трябва да съдържа поне 1 символ"
} }
}, },
"import": { "import": {
@ -23,7 +23,7 @@
"channelPrefix": "Канал: ", "channelPrefix": "Канал: ",
"channelSetUrl": "Channel Set/QR Code URL", "channelSetUrl": "Channel Set/QR Code URL",
"channels": "Канали:", "channels": "Канали:",
"usePreset": "Use Preset?", "usePreset": "Използване на предварително зададени настройки?",
"title": "Import Channel Set" "title": "Import Channel Set"
}, },
"locationResponse": { "locationResponse": {
@ -68,11 +68,11 @@
"bluetoothConnection": { "bluetoothConnection": {
"noDevicesPaired": "Все още няма сдвоени устройства.", "noDevicesPaired": "Все още няма сдвоени устройства.",
"newDeviceButton": "Ново устройство", "newDeviceButton": "Ново устройство",
"connectionFailed": "Connection failed", "connectionFailed": "Връзката е неуспешна",
"deviceDisconnected": "Device disconnected", "deviceDisconnected": "Устройството не е свързано",
"unknownDevice": "Неизвестно устройство", "unknownDevice": "Неизвестно устройство",
"errorLoadingDevices": "Error loading devices", "errorLoadingDevices": "Грешка при зареждане на устройствата",
"unknownErrorLoadingDevices": "Unknown error loading devices" "unknownErrorLoadingDevices": "Неизвестна грешка при зареждане на устройствата"
}, },
"validation": { "validation": {
"requiresFeatures": "Този тип връзка изисква <0></0>. Моля, използвайте поддържан браузър, като Chrome или Edge.", "requiresFeatures": "Този тип връзка изисква <0></0>. Моля, използвайте поддържан браузър, като Chrome или Edge.",
@ -116,7 +116,7 @@
"pkiBackupReminder": { "pkiBackupReminder": {
"description": "Препоръчваме редовно да правите резервни копия на данните с вашите ключове. Искате ли да направите резервно копие сега?", "description": "Препоръчваме редовно да правите резервни копия на данните с вашите ключове. Искате ли да направите резервно копие сега?",
"title": "Напомняне за резервно копие", "title": "Напомняне за резервно копие",
"remindLaterPrefix": "Remind me in", "remindLaterPrefix": "Напомни ми в",
"remindNever": "Никога не ми напомняй", "remindNever": "Никога не ми напомняй",
"backupNow": "Създаване на резервно копие сега" "backupNow": "Създаване на резервно копие сега"
}, },

12
packages/web/public/i18n/locales/bg-BG/messages.json

@ -1,14 +1,14 @@
{ {
"page": { "page": {
"title": "Съобщения: {{chatName}}", "title": "Съобщения: {{chatName}}",
"placeholder": "Enter Message" "placeholder": "Въведете съобщение"
}, },
"emptyState": { "emptyState": {
"title": "Изберете чат", "title": "Изберете чат",
"text": "Все още няма съобщения." "text": "Все още няма съобщения."
}, },
"selectChatPrompt": { "selectChatPrompt": {
"text": "Select a channel or node to start messaging." "text": "Изберете канал или възел, за да стартирате съобщения."
}, },
"sendMessage": { "sendMessage": {
"placeholder": "Въведете Вашето съобщение тук...", "placeholder": "Въведете Вашето съобщение тук...",
@ -24,16 +24,16 @@
"displayText": "Съобщението е доставено" "displayText": "Съобщението е доставено"
}, },
"failed": { "failed": {
"label": "Message delivery failed", "label": "Доставката на съобщението не е успешна",
"displayText": "Delivery failed" "displayText": "Неуспешна доставка"
}, },
"unknown": { "unknown": {
"label": "Статусът на съобщението е неизвестен", "label": "Статусът на съобщението е неизвестен",
"displayText": "Неизвестно състояние" "displayText": "Неизвестно състояние"
}, },
"waiting": { "waiting": {
"label": "Sending message", "label": "Изпращане на съобщение",
"displayText": "Waiting for delivery" "displayText": "Чака доставка"
} }
} }
} }

4
packages/web/public/i18n/locales/bg-BG/moduleConfig.json

@ -45,8 +45,8 @@
"description": "Enable Codec 2 audio encoding" "description": "Enable Codec 2 audio encoding"
}, },
"pttPin": { "pttPin": {
"label": "PTT Pin", "label": "Пин за РТТ",
"description": "GPIO pin to use for PTT" "description": "GPIO пин, който да се използва за PTT"
}, },
"bitrate": { "bitrate": {
"label": "Bitrate", "label": "Bitrate",

4
packages/web/public/i18n/locales/bg-BG/nodes.json

@ -28,10 +28,10 @@
"label": "Височина" "label": "Височина"
}, },
"channelUtil": { "channelUtil": {
"label": "Channel Util" "label": "Използване на канала"
}, },
"airtimeUtil": { "airtimeUtil": {
"label": "Airtime Util" "label": "Използване на ефирно време"
} }
}, },
"nodesTable": { "nodesTable": {

10
packages/web/public/i18n/locales/bg-BG/ui.json

@ -136,7 +136,7 @@
"label": "Филтър" "label": "Филтър"
}, },
"advanced": { "advanced": {
"label": "Advanced" "label": "Разширени"
}, },
"clearInput": { "clearInput": {
"label": "Clear input" "label": "Clear input"
@ -149,7 +149,7 @@
"placeholder": "Meshtastic 1234" "placeholder": "Meshtastic 1234"
}, },
"airtimeUtilization": { "airtimeUtilization": {
"label": "Airtime Utilization (%)" "label": "Използване на ефира (%)"
}, },
"batteryLevel": { "batteryLevel": {
"label": "Ниво на батерията (%)", "label": "Ниво на батерията (%)",
@ -179,16 +179,16 @@
"label": "Любими" "label": "Любими"
}, },
"hide": { "hide": {
"label": "Hide" "label": "Скриване"
}, },
"showOnly": { "showOnly": {
"label": "Show Only" "label": "Показване само"
}, },
"viaMqtt": { "viaMqtt": {
"label": "Свързан чрез MQTT" "label": "Свързан чрез MQTT"
}, },
"hopsUnknown": { "hopsUnknown": {
"label": "Unknown number of hops" "label": "Неизвестен брой хопове"
}, },
"showUnheard": { "showUnheard": {
"label": "Never heard" "label": "Never heard"

1
packages/web/public/i18n/locales/en/commandPalette.json

@ -35,6 +35,7 @@
"scheduleShutdown": "Schedule Shutdown", "scheduleShutdown": "Schedule Shutdown",
"scheduleReboot": "Reboot Device", "scheduleReboot": "Reboot Device",
"resetNodeDb": "Reset Node DB", "resetNodeDb": "Reset Node DB",
"dfuMode": "Enter DFU Mode",
"factoryResetDevice": "Factory Reset Device", "factoryResetDevice": "Factory Reset Device",
"factoryResetConfig": "Factory Reset Config", "factoryResetConfig": "Factory Reset Config",
"disconnect": "Disconnect" "disconnect": "Disconnect"

5
packages/web/public/i18n/locales/en/dialog.json

@ -76,8 +76,9 @@
"unknownErrorLoadingDevices": "Unknown error loading devices" "unknownErrorLoadingDevices": "Unknown error loading devices"
}, },
"validation": { "validation": {
"requiresFeatures": "This connection type requires <0></0>. Please use a supported browser, like Chrome or Edge.", "requiresWebBluetooth": "This connection type requires <0>Web Bluetooth</0>. Please use a supported browser, like Chrome or Edge.",
"requiresSecureContext": "This application requires a <0>secure context</0>. Please connect using HTTPS or localhost.", "requiresWebSerial": "This connection type requires <0>Web Serial</0>. Please use a supported browser, like Chrome or Edge.",
"requiresSecureContext": "This application requires a <0>secure context</0>. Please connect using HTTPS or localhost.",
"additionallyRequiresSecureContext": "Additionally, it requires a <0>secure context</0>. Please connect using HTTPS or localhost." "additionallyRequiresSecureContext": "Additionally, it requires a <0>secure context</0>. Please connect using HTTPS or localhost."
} }
}, },

8
packages/web/src/components/CommandPalette/index.tsx

@ -24,6 +24,7 @@ import {
CloudOff, CloudOff,
EraserIcon, EraserIcon,
FactoryIcon, FactoryIcon,
HardDriveUpload,
LayersIcon, LayersIcon,
LinkIcon, LinkIcon,
type LucideIcon, type LucideIcon,
@ -194,6 +195,13 @@ export const CommandPalette = () => {
setDialogOpen("reboot", true); setDialogOpen("reboot", true);
}, },
}, },
{
label: t("contextual.command.dfuMode"),
icon: HardDriveUpload,
action() {
connection?.enterDfuMode()
},
},
{ {
label: t("contextual.command.resetNodeDb"), label: t("contextual.command.resetNodeDb"),
icon: TrashIcon, icon: TrashIcon,

331
pnpm-lock.yaml

@ -61,6 +61,15 @@ importers:
specifier: workspace:* specifier: workspace:*
version: link:../core version: link:../core
packages/transport-node-serial:
dependencies:
'@meshtastic/core':
specifier: workspace:*
version: link:../core
serialport:
specifier: ^13.0.0
version: 13.0.0
packages/transport-web-bluetooth: packages/transport-web-bluetooth:
dependencies: dependencies:
'@meshtastic/core': '@meshtastic/core':
@ -812,12 +821,12 @@ packages:
resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
engines: {node: '>= 8'} engines: {node: '>= 8'}
'@oxc-project/[email protected]0.0': '@oxc-project/[email protected]2.2':
resolution: {integrity: sha512-3rzy1bJAZ4s7zV9TKT60x119RwJDCDqEtCwK/Zc2qlm7wGhiIUxLLYUhE/mN91yB0u1kxm5sh4NjU12sPqQTpg==} resolution: {integrity: sha512-cYxcj5CPn/vo5QSpCZcYzBiLidU5+GlFSqIeNaMgBDtcVRBsBJHZg3pHw999W6nHamFQ1EHuPPByB26tjaJiJw==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
'@oxc-project/[email protected]0.0': '@oxc-project/[email protected]2.2':
resolution: {integrity: sha512-xxHQm8wfCv2e8EmtaDwpMeAHOWqgQDAYg+BJouLXSQt5oTKu9TIXrgNMGSrM2fLvKmECsRd9uUFAAD+hPyootA==} resolution: {integrity: sha512-WMGSwd9FsNBs/WfqIOH0h3k1LBdjZJQGYjGnC+vla/fh6HUsu5HzGPerRljiq1hgMQ6gs031YJR12VyP57b/hQ==}
'@quansync/[email protected]': '@quansync/[email protected]':
resolution: {integrity: sha512-vy/41FCdnIalPTQCb2Wl0ic1caMdzGus4ktDp+gpZesQNydXcx8nhh8qB3qMPbGkictOTaXgXEUUfQEm8DQYoA==} resolution: {integrity: sha512-vy/41FCdnIalPTQCb2Wl0ic1caMdzGus4ktDp+gpZesQNydXcx8nhh8qB3qMPbGkictOTaXgXEUUfQEm8DQYoA==}
@ -1334,81 +1343,81 @@ packages:
'@radix-ui/[email protected]': '@radix-ui/[email protected]':
resolution: {integrity: sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==} resolution: {integrity: sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==}
'@rolldown/[email protected]1': '@rolldown/[email protected]3':
resolution: {integrity: sha512-0mFtKwOG7smn0HkvQ6h8j0m/ohkR7Fp5eMTJ2Pns/HSbePHuDpxMaQ4TjZ6arlVXxpeWZlAHeT5BeNsOA3iWTg==} resolution: {integrity: sha512-xhDQXKftRkEULIxCddrKMR8y0YO/Y+6BKk/XrQP2B29YjV2wr8DByoEz+AHX9BfLHb2srfpdN46UquBW2QXWpQ==}
cpu: [arm64] cpu: [arm64]
os: [android] os: [android]
'@rolldown/[email protected]1': '@rolldown/[email protected]3':
resolution: {integrity: sha512-BHfHJ8Nb5G7ZKJl6pimJacupONT4F7w6gmQHw41rouAnJF51ORDwGefWeb6OMLzGmJwzxlIVPERfnJf1EsMM7A==} resolution: {integrity: sha512-7lhhY08v5ZtRq8JJQaJ49fnJombAPnqllKKCDLU/UvaqNAOEyTGC8J1WVOLC4EA4zbXO5U3CCRgVGyAFNH2VtQ==}
cpu: [arm64] cpu: [arm64]
os: [darwin] os: [darwin]
'@rolldown/[email protected]1': '@rolldown/[email protected]3':
resolution: {integrity: sha512-4MiuRtExC08jHbSU/diIL+IuQP+3Ck1FbWAplK+ysQJ7fxT3DMxy5FmnIGfmhaqow8oTjb2GEwZJKgTRjZL1Vw==} resolution: {integrity: sha512-U2iGjcDV7NWyYyhap8YuY0nwrLX6TvX/9i7gBtdEMPm9z3wIUVGNMVdGlA43uqg7xDpRGpEqGnxbeDgiEwYdnA==}
cpu: [x64] cpu: [x64]
os: [darwin] os: [darwin]
'@rolldown/[email protected]1': '@rolldown/[email protected]3':
resolution: {integrity: sha512-nffC1u7ccm12qlAea8ExY3AvqlaHy/o/3L4p5Es8JFJ3zJSs6e3DyuxGZZVdl9EVwsLxPPTvioIl4tEm2afwyw==} resolution: {integrity: sha512-gd6ASromVHFLlzrjJWMG5CXHkS7/36DEZ8HhvGt2NN8eZALCIuyEx8HMMLqvKA7z4EAztVkdToVrdxpGMsKZxw==}
cpu: [x64] cpu: [x64]
os: [freebsd] os: [freebsd]
'@rolldown/[email protected]1': '@rolldown/[email protected]3':
resolution: {integrity: sha512-LHmAaB3rB1GOJuHscKcL2Ts/LKLcb3YWTh2uQ/876rg/J9WE9kQ0kZ+3lRSYbth/YL8ln54j4JZmHpqQY3xptQ==} resolution: {integrity: sha512-xmeLfkfGthuynO1EpCdyTVr0r4G+wqvnKCuyR6rXOet+hLrq5HNAC2XtP/jU2TB4Bc6aiLYxl868B8CGtFDhcw==}
cpu: [arm] cpu: [arm]
os: [linux] os: [linux]
'@rolldown/[email protected]1': '@rolldown/[email protected]3':
resolution: {integrity: sha512-oTDZVfqIAjLB2I1yTiLyyhfPPO6dky33sTblxTCpe+ZT55WizN3KDoBKJ4yXG8shI6I4bRShVu29Xg0yAjyQYw==} resolution: {integrity: sha512-cHGp8yfHL4pes6uaLbO5L58ceFkUK4efd8iE86jClD1QPPDLKiqEXJCFYeuK3OfODuF5EBOmf0SlcUZNEYGdmw==}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
'@rolldown/[email protected]1': '@rolldown/[email protected]3':
resolution: {integrity: sha512-duJ3IkEBj9Xe9NYW1n8Y3483VXHGi8zQ0ZsLbK8464EJUXLF7CXM8Ry+jkkUw+ZvA+Zu1E/+C6p2Y6T9el0C9g==} resolution: {integrity: sha512-wZ1t7JAvVeFgskH1L9y7c47ITitPytpL0s8FmAT8pVfXcaTmS58ZyoXT+y6cz8uCkQnETjrX3YezTGI18u3ecg==}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
'@rolldown/[email protected]': '@rolldown/[email protected]':
resolution: {integrity: sha512-qdbmU5QSZ0uoLZBYMxiHsMQmizqtzFGTVPU5oyU1n0jU0Mo+mkSzqZuL8VBnjHOHzhVxZsoAGH9JjiRzCnoGVA==} resolution: {integrity: sha512-cDndWo3VEYbm7yeujOV6Ie2XHz0K8YX/R/vbNmMo03m1QwtBKKvbYNSyJb3B9+8igltDjd8zNM9mpiNNrq/ekQ==}
cpu: [arm64]
os: [openharmony]
'@rolldown/[email protected]':
resolution: {integrity: sha512-H7+r34TSV8udB2gAsebFM/YuEeNCkPGEAGJ1JE7SgI9XML6FflqcdKfrRSneQFsPaom/gCEc1g0WW5MZ0O3blw==}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
'@rolldown/[email protected]1': '@rolldown/[email protected]':
resolution: {integrity: sha512-zRm2YmzFVqbsmUsyyZnHfJrOlQUcWS/FJ5ZWL8Q1kZh5PnLBrTVZNpakIWwAxpN5gNEi9MmFd5YHocVJp8ps1Q==} resolution: {integrity: sha512-bl7uzi6es/l6LT++NZcBpiX43ldLyKXCPwEZGY1rZJ99HQ7m1g3KxWwYCcGxtKjlb2ExVvDZicF6k+96vxOJKg==}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
'@rolldown/[email protected]': '@rolldown/[email protected]':
resolution: {integrity: sha512-fM1eUIuHLsNJXRlWOuIIex1oBJ89I0skFWo5r/D3KSJ5gD9MBd3g4Hp+v1JGohvyFE+7ylnwRxSUyMEeYpA69A==} resolution: {integrity: sha512-TrgzQanpLgcmmzolCbYA9BPZgF1gYxkIGZhU/HROnJPsq67gcyaYw/JBLioqQLjIwMipETkn25YY799D2OZzJA==}
cpu: [arm64]
os: [openharmony]
'@rolldown/[email protected]':
resolution: {integrity: sha512-z0LltdUfvoKak9SuaLz/M9AVSg+RTOZjFksbZXzC6Svl1odyW4ai21VHhZy3m2Faeeb/rl/9efVLayj+qYEGxw==}
engines: {node: '>=14.0.0'} engines: {node: '>=14.0.0'}
cpu: [wasm32] cpu: [wasm32]
'@rolldown/[email protected]': '@rolldown/[email protected]3':
resolution: {integrity: sha512-4nftR9V2KHH3zjBwf6leuZZJQZ7v0d70ogjHIqB3SDsbDLvVEZiGSsSn2X6blSZRZeJSFzK0pp4kZ67zdZXwSw==} resolution: {integrity: sha512-CpvOHyqDNOYx9riD4giyXQDIu72bWRU2Dwt1xFSPlBudk6NumK0OJl6Ch+LPnkp5podQHcQg0mMauAXPVKct7g==}
cpu: [arm64] cpu: [arm64]
os: [win32] os: [win32]
'@rolldown/[email protected]1': '@rolldown/[email protected]3':
resolution: {integrity: sha512-0TQcKu9xZVHYALit+WJsSuADGlTFfOXhnZoIHWWQhTk3OgbwwbYcSoZUXjRdFmR6Wswn4csHtJGN1oYKeQ6/2g==} resolution: {integrity: sha512-/tNTvZTWHz6HiVuwpR3zR0kGIyCNb+/tFhnJmti+Aw2fAXs3l7Aj0DcXd0646eFKMX8L2w5hOW9H08FXTUkN0g==}
cpu: [ia32] cpu: [ia32]
os: [win32] os: [win32]
'@rolldown/[email protected]1': '@rolldown/[email protected]3':
resolution: {integrity: sha512-3zMICWwpZh1jrkkKDYIUCx/2wY3PXLICAS0AnbeLlhzfWPhCcpNK9eKhiTlLAZyTp+3kyipoi/ZSVIh+WDnBpQ==} resolution: {integrity: sha512-Bb2qK3z7g2mf4zaKRvkohHzweaP1lLbaoBmXZFkY6jJWMm0Z8Pfnh8cOoRlH1IVM1Ufbo8ZZ1WXp1LbOpRMtXw==}
cpu: [x64] cpu: [x64]
os: [win32] os: [win32]
'@rolldown/[email protected]': '@rolldown/[email protected]':
resolution: {integrity: sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==} resolution: {integrity: sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==}
'@rolldown/[email protected]1': '@rolldown/[email protected]3':
resolution: {integrity: sha512-IaDZ9NhjOIOkYtm+hH0GX33h3iVZ2OeSUnFF0+7Z4+1GuKs4Kj5wK3+I2zNV9IPLfqV4XlwWif8SXrZNutxciQ==} resolution: {integrity: sha512-she25NCG6NoEPC/SEB4pHs5STcnfI4VBFOzjeI63maSPrWME5J2XC8ogrBgp8NaE/xzj28/kbpSaebiMvFRj+w==}
'@rollup/[email protected]': '@rollup/[email protected]':
resolution: {integrity: sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==} resolution: {integrity: sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==}
@ -1514,6 +1523,70 @@ packages:
cpu: [x64] cpu: [x64]
os: [win32] os: [win32]
'@serialport/[email protected]':
resolution: {integrity: sha512-HAFzGhk9OuFMpuor7aT5G1ChPgn5qSsklTFOTUX72Rl6p0xwcSVsRtG/xaGp6bxpN7fI9D/S8THLBWbBgS6ldw==}
engines: {node: '>=12.0.0'}
'@serialport/[email protected]':
resolution: {integrity: sha512-r25o4Bk/vaO1LyUfY/ulR6hCg/aWiN6Wo2ljVlb4Pj5bqWGcSRC4Vse4a9AcapuAu/FeBzHCbKMvRQeCuKjzIQ==}
engines: {node: '>=18.0.0'}
'@serialport/[email protected]':
resolution: {integrity: sha512-CJaUd5bLvtM9c5dmO9rPBHPXTa9R2UwpkJ0wdh9JCYcbrPWsKz+ErvR0hBLeo7NPeiFdjFO4sonRljiw4d2XiA==}
engines: {node: ^12.22 || ^14.13 || >=16}
'@serialport/[email protected]':
resolution: {integrity: sha512-32yvqeTAqJzAEtX5zCrN1Mej56GJ5h/cVFsCDPbF9S1ZSC9FWjOqNAgtByseHfFTSTs/4ZBQZZcZBpolt8sUng==}
engines: {node: '>=20.0.0'}
'@serialport/[email protected]':
resolution: {integrity: sha512-RErAe57g9gvnlieVYGIn1xymb1bzNXb2QtUQd14FpmbQQYlcrmuRnJwKa1BgTCujoCkhtaTtgHlbBWOxm8U2uA==}
engines: {node: '>=20.0.0'}
'@serialport/[email protected]':
resolution: {integrity: sha512-gu26tVt5lQoybhorLTPsH2j2LnX3AOP2x/34+DUSTNaUTzu2fBXw+isVjQJpUBFWu6aeQRZw5bJol5X9Gxjblw==}
engines: {node: '>=12.0.0'}
'@serialport/[email protected]':
resolution: {integrity: sha512-Qqyb0FX1avs3XabQqNaZSivyVbl/yl0jywImp7ePvfZKLwx7jBZjvL+Hawt9wIG6tfq6zbFM24vzCCK7REMUig==}
engines: {node: '>=20.0.0'}
'@serialport/[email protected]':
resolution: {integrity: sha512-a0w0WecTW7bD2YHWrpTz1uyiWA2fDNym0kjmPeNSwZ2XCP+JbirZt31l43m2ey6qXItTYVuQBthm75sPVeHnGA==}
engines: {node: '>=20.0.0'}
'@serialport/[email protected]':
resolution: {integrity: sha512-60ZDDIqYRi0Xs2SPZUo4Jr5LLIjtb+rvzPKMJCohrO6tAqSDponcNpcB1O4W21mKTxYjqInSz+eMrtk0LLfZIg==}
engines: {node: '>=8.6.0'}
'@serialport/[email protected]':
resolution: {integrity: sha512-O7cywCWC8PiOMvo/gglEBfAkLjp/SENEML46BXDykfKP5mTPM46XMaX1L0waWU6DXJpBgjaL7+yX6VriVPbN4w==}
engines: {node: '>=12.0.0'}
'@serialport/[email protected]':
resolution: {integrity: sha512-dov3zYoyf0dt1Sudd1q42VVYQ4WlliF0MYvAMA3MOyiU1IeG4hl0J6buBA2w4gl3DOCC05tGgLDN/3yIL81gsA==}
engines: {node: '>=20.0.0'}
'@serialport/[email protected]':
resolution: {integrity: sha512-JNUQA+y2Rfs4bU+cGYNqOPnNMAcayhhW+XJZihSLQXOHcZsFnOa2F9YtMg9VXRWIcnHldHYtisp62Etjlw24bw==}
engines: {node: '>=20.0.0'}
'@serialport/[email protected]':
resolution: {integrity: sha512-m7HpIf56G5XcuDdA3DB34Z0pJiwxNRakThEHjSa4mG05OnWYv0IG8l2oUyYfuGMowQWaVnQ+8r+brlPxGVH+eA==}
engines: {node: '>=20.0.0'}
'@serialport/[email protected]':
resolution: {integrity: sha512-fUHZEExm6izJ7rg0A1yjXwu4sOzeBkPAjDZPfb+XQoqgtKAk+s+HfICiYn7N2QU9gyaeCO8VKgWwi+b/DowYOg==}
engines: {node: '>=20.0.0'}
'@serialport/[email protected]':
resolution: {integrity: sha512-DoXJ3mFYmyD8X/8931agJvrBPxqTaYDsPoly9/cwQSeh/q4EjQND9ySXBxpWz5WcpyCU4jOuusqCSAPsbB30Eg==}
engines: {node: '>=20.0.0'}
'@serialport/[email protected]':
resolution: {integrity: sha512-F7xLJKsjGo2WuEWMSEO1SimRcOA+WtWICsY13r0ahx8s2SecPQH06338g28OT7cW7uRXI7oEQAk62qh5gHJW3g==}
engines: {node: '>=20.0.0'}
'@standard-schema/[email protected]': '@standard-schema/[email protected]':
resolution: {integrity: sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==} resolution: {integrity: sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==}
@ -2546,6 +2619,15 @@ packages:
resolution: {integrity: sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==} resolution: {integrity: sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==}
engines: {node: '>=0.10'} engines: {node: '>=0.10'}
[email protected]:
resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==}
engines: {node: '>=6.0'}
peerDependencies:
supports-color: '*'
peerDependenciesMeta:
supports-color:
optional: true
[email protected]: [email protected]:
resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==} resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==}
engines: {node: '>=6.0'} engines: {node: '>=6.0'}
@ -3219,6 +3301,10 @@ packages:
no-[email protected]: no-[email protected]:
resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==} resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==}
[email protected]:
resolution: {integrity: sha512-8VOpLHFrOQlAH+qA0ZzuGRlALRA6/LVh8QJldbrC4DY0hXoMP0l4Acq8TzFC018HztWiRqyCEj2aTWY2UvnJUg==}
engines: {node: ^18 || ^20 || >= 21}
[email protected]: [email protected]:
resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==}
engines: {node: 4.x || >=6.0.0} engines: {node: 4.x || >=6.0.0}
@ -3228,6 +3314,10 @@ packages:
encoding: encoding:
optional: true optional: true
[email protected]:
resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==}
hasBin: true
[email protected]: [email protected]:
resolution: {integrity: sha512-RaBPP3+51hPne/OolXxcz89iYvQvKOydaqoePpOgXcrOKZhjVIzmpKZz+Hd/RBO2/zN2q6CNJhQzucVz+u3Jyw==} resolution: {integrity: sha512-RaBPP3+51hPne/OolXxcz89iYvQvKOydaqoePpOgXcrOKZhjVIzmpKZz+Hd/RBO2/zN2q6CNJhQzucVz+u3Jyw==}
@ -3563,8 +3653,8 @@ packages:
vue-tsc: vue-tsc:
optional: true optional: true
[email protected]1: [email protected]3:
resolution: {integrity: sha512-M2Q+RfG0FMJeSW3RSFTbvtjGVTcQpTQvN247D0EMSsPkpZFoinopR9oAnQiwgogQyzDuvKNnbyCbQQlmNAzSoQ==} resolution: {integrity: sha512-mgu118ZuRguC8unhPCbdZbyRbjQfEMiWqlojBA5aRIncBelRaBomnHNpGKYkYWeK7twRz5Cql30xgqqrA3Xelw==}
hasBin: true hasBin: true
[email protected]: [email protected]:
@ -3609,6 +3699,10 @@ packages:
engines: {node: '>=10'} engines: {node: '>=10'}
hasBin: true hasBin: true
[email protected]:
resolution: {integrity: sha512-PHpnTd8isMGPfFTZNCzOZp9m4mAJSNWle9Jxu6BPTcWq7YXl5qN7tp8Sgn0h+WIGcD6JFz5QDgixC2s4VW7vzg==}
engines: {node: '>=20.0.0'}
[email protected]: [email protected]:
resolution: {integrity: sha512-0QvCV2lM3aj/U3YozDiVwx9zpH0q8A60CTWIv4Jszj/givcudPb48B+rkU5D51NJ0pTpweGMttHjboPa9/zoIQ==} resolution: {integrity: sha512-0QvCV2lM3aj/U3YozDiVwx9zpH0q8A60CTWIv4Jszj/givcudPb48B+rkU5D51NJ0pTpweGMttHjboPa9/zoIQ==}
engines: {node: '>=10'} engines: {node: '>=10'}
@ -4604,9 +4698,9 @@ snapshots:
'@nodelib/fs.scandir': 2.1.5 '@nodelib/fs.scandir': 2.1.5
fastq: 1.19.1 fastq: 1.19.1
'@oxc-project/[email protected]0.0': {} '@oxc-project/[email protected]2.2': {}
'@oxc-project/[email protected]0.0': {} '@oxc-project/[email protected]2.2': {}
'@quansync/[email protected]': '@quansync/[email protected]':
dependencies: dependencies:
@ -5161,53 +5255,53 @@ snapshots:
'@radix-ui/[email protected]': {} '@radix-ui/[email protected]': {}
'@rolldown/[email protected]1': '@rolldown/[email protected]3':
optional: true optional: true
'@rolldown/[email protected]1': '@rolldown/[email protected]3':
optional: true optional: true
'@rolldown/[email protected]1': '@rolldown/[email protected]3':
optional: true optional: true
'@rolldown/[email protected]1': '@rolldown/[email protected]3':
optional: true optional: true
'@rolldown/[email protected]1': '@rolldown/[email protected]3':
optional: true optional: true
'@rolldown/[email protected]1': '@rolldown/[email protected]3':
optional: true optional: true
'@rolldown/[email protected]1': '@rolldown/[email protected]3':
optional: true optional: true
'@rolldown/binding-linux-[email protected]': '@rolldown/binding-linux-[email protected]':
optional: true optional: true
'@rolldown/binding-linux-x64-[email protected]': '@rolldown/binding-linux-x64-[email protected]':
optional: true optional: true
'@rolldown/binding-[email protected]': '@rolldown/binding-[email protected]':
optional: true optional: true
'@rolldown/[email protected]1': '@rolldown/[email protected]3':
dependencies: dependencies:
'@napi-rs/wasm-runtime': 1.0.3 '@napi-rs/wasm-runtime': 1.0.3
optional: true optional: true
'@rolldown/[email protected]1': '@rolldown/[email protected]3':
optional: true optional: true
'@rolldown/[email protected]1': '@rolldown/[email protected]3':
optional: true optional: true
'@rolldown/[email protected]1': '@rolldown/[email protected]3':
optional: true optional: true
'@rolldown/[email protected]': {} '@rolldown/[email protected]': {}
'@rolldown/[email protected]1': {} '@rolldown/[email protected]3': {}
'@rollup/[email protected]': '@rollup/[email protected]':
dependencies: dependencies:
@ -5274,6 +5368,60 @@ snapshots:
'@rollup/[email protected]': '@rollup/[email protected]':
optional: true optional: true
'@serialport/[email protected]':
dependencies:
'@serialport/bindings-interface': 1.2.2
debug: 4.4.1
transitivePeerDependencies:
- supports-color
'@serialport/[email protected]':
dependencies:
'@serialport/bindings-interface': 1.2.2
'@serialport/parser-readline': 12.0.0
debug: 4.4.0
node-addon-api: 8.3.0
node-gyp-build: 4.8.4
transitivePeerDependencies:
- supports-color
'@serialport/[email protected]': {}
'@serialport/[email protected]': {}
'@serialport/[email protected]': {}
'@serialport/[email protected]': {}
'@serialport/[email protected]': {}
'@serialport/[email protected]': {}
'@serialport/[email protected]': {}
'@serialport/[email protected]':
dependencies:
'@serialport/parser-delimiter': 12.0.0
'@serialport/[email protected]':
dependencies:
'@serialport/parser-delimiter': 13.0.0
'@serialport/[email protected]': {}
'@serialport/[email protected]': {}
'@serialport/[email protected]': {}
'@serialport/[email protected]': {}
'@serialport/[email protected]':
dependencies:
'@serialport/bindings-interface': 1.2.2
debug: 4.4.0
transitivePeerDependencies:
- supports-color
'@standard-schema/[email protected]': {} '@standard-schema/[email protected]': {}
'@tailwindcss/[email protected]': '@tailwindcss/[email protected]':
@ -7108,6 +7256,10 @@ snapshots:
dependencies: dependencies:
assert-plus: 1.0.0 assert-plus: 1.0.0
[email protected]:
dependencies:
ms: 2.1.3
[email protected]: [email protected]:
dependencies: dependencies:
ms: 2.1.3 ms: 2.1.3
@ -7749,10 +7901,14 @@ snapshots:
lower-case: 2.0.2 lower-case: 2.0.2
tslib: 2.8.1 tslib: 2.8.1
[email protected]: {}
[email protected]: [email protected]:
dependencies: dependencies:
whatwg-url: 5.0.0 whatwg-url: 5.0.0
[email protected]: {}
[email protected]: [email protected]:
dependencies: dependencies:
css-select: 4.3.0 css-select: 4.3.0
@ -8056,7 +8212,7 @@ snapshots:
[email protected]: {} [email protected]: {}
[email protected]([email protected]1)([email protected]): [email protected]([email protected]3)([email protected]):
dependencies: dependencies:
'@babel/generator': 7.28.0 '@babel/generator': 7.28.0
'@babel/parser': 7.28.0 '@babel/parser': 7.28.0
@ -8066,34 +8222,34 @@ snapshots:
debug: 4.4.1 debug: 4.4.1
dts-resolver: 2.1.1 dts-resolver: 2.1.1
get-tsconfig: 4.10.1 get-tsconfig: 4.10.1
rolldown: 1.0.0-beta.31 rolldown: 1.0.0-beta.33
optionalDependencies: optionalDependencies:
typescript: 5.9.2 typescript: 5.9.2
transitivePeerDependencies: transitivePeerDependencies:
- oxc-resolver - oxc-resolver
- supports-color - supports-color
[email protected]1: [email protected]3:
dependencies: dependencies:
'@oxc-project/runtime': 0.80.0 '@oxc-project/runtime': 0.82.2
'@oxc-project/types': 0.80.0 '@oxc-project/types': 0.82.2
'@rolldown/pluginutils': 1.0.0-beta.31 '@rolldown/pluginutils': 1.0.0-beta.33
ansis: 4.1.0 ansis: 4.1.0
optionalDependencies: optionalDependencies:
'@rolldown/binding-android-arm64': 1.0.0-beta.31 '@rolldown/binding-android-arm64': 1.0.0-beta.33
'@rolldown/binding-darwin-arm64': 1.0.0-beta.31 '@rolldown/binding-darwin-arm64': 1.0.0-beta.33
'@rolldown/binding-darwin-x64': 1.0.0-beta.31 '@rolldown/binding-darwin-x64': 1.0.0-beta.33
'@rolldown/binding-freebsd-x64': 1.0.0-beta.31 '@rolldown/binding-freebsd-x64': 1.0.0-beta.33
'@rolldown/binding-linux-arm-gnueabihf': 1.0.0-beta.31 '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-beta.33
'@rolldown/binding-linux-arm64-gnu': 1.0.0-beta.31 '@rolldown/binding-linux-arm64-gnu': 1.0.0-beta.33
'@rolldown/binding-linux-arm64-musl': 1.0.0-beta.31 '@rolldown/binding-linux-arm64-musl': 1.0.0-beta.33
'@rolldown/binding-linux-arm64-ohos': 1.0.0-beta.31 '@rolldown/binding-linux-x64-gnu': 1.0.0-beta.33
'@rolldown/binding-linux-x64-gnu': 1.0.0-beta.31 '@rolldown/binding-linux-x64-musl': 1.0.0-beta.33
'@rolldown/binding-linux-x64-musl': 1.0.0-beta.31 '@rolldown/binding-openharmony-arm64': 1.0.0-beta.33
'@rolldown/binding-wasm32-wasi': 1.0.0-beta.31 '@rolldown/binding-wasm32-wasi': 1.0.0-beta.33
'@rolldown/binding-win32-arm64-msvc': 1.0.0-beta.31 '@rolldown/binding-win32-arm64-msvc': 1.0.0-beta.33
'@rolldown/binding-win32-ia32-msvc': 1.0.0-beta.31 '@rolldown/binding-win32-ia32-msvc': 1.0.0-beta.33
'@rolldown/binding-win32-x64-msvc': 1.0.0-beta.31 '@rolldown/binding-win32-x64-msvc': 1.0.0-beta.33
[email protected]: [email protected]:
dependencies: dependencies:
@ -8149,6 +8305,25 @@ snapshots:
[email protected]: {} [email protected]: {}
[email protected]:
dependencies:
'@serialport/binding-mock': 10.2.2
'@serialport/bindings-cpp': 13.0.0
'@serialport/parser-byte-length': 13.0.0
'@serialport/parser-cctalk': 13.0.0
'@serialport/parser-delimiter': 13.0.0
'@serialport/parser-inter-byte-timeout': 13.0.0
'@serialport/parser-packet-length': 13.0.0
'@serialport/parser-readline': 13.0.0
'@serialport/parser-ready': 13.0.0
'@serialport/parser-regex': 13.0.0
'@serialport/parser-slip-encoder': 13.0.0
'@serialport/parser-spacepacket': 13.0.0
'@serialport/stream': 13.0.0
debug: 4.4.0
transitivePeerDependencies:
- supports-color
[email protected]([email protected]): [email protected]([email protected]):
dependencies: dependencies:
seroval: 1.3.2 seroval: 1.3.2
@ -8387,8 +8562,8 @@ snapshots:
diff: 8.0.2 diff: 8.0.2
empathic: 2.0.0 empathic: 2.0.0
hookable: 5.5.3 hookable: 5.5.3
rolldown: 1.0.0-beta.31 rolldown: 1.0.0-beta.33
rolldown-plugin-dts: 0.15.6([email protected]1)([email protected]) rolldown-plugin-dts: 0.15.6([email protected]3)([email protected])
semver: 7.7.2 semver: 7.7.2
tinyexec: 1.0.1 tinyexec: 1.0.1
tinyglobby: 0.2.14 tinyglobby: 0.2.14

Loading…
Cancel
Save