diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index e31c47fc..afe97483 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,12 +1,13 @@ { "name": "bitvid", - "image": "mcr.microsoft.com/devcontainers/javascript-node:20", - "postCreateCommand": "npm ci", + "image": "mcr.microsoft.com/devcontainers/javascript-node:22", + "postCreateCommand": "npm ci && npm run build", "customizations": { "vscode": { "extensions": [ "esbenp.prettier-vscode", - "bradlc.vscode-tailwindcss" + "bradlc.vscode-tailwindcss", + "stylelint.vscode-stylelint" ] } } diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 47b92474..35ae9828 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -76,3 +76,123 @@ jobs: - name: Fail if visual regressions detected if: steps.visual.outcome == 'failure' run: exit 1 + + dm-unit-tests: + runs-on: ubuntu-latest + strategy: + matrix: + node-version: [20] + + steps: + - name: Check out repository + uses: actions/checkout@v4 + + - name: Set up Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + + - name: Cache npm directory + uses: actions/cache@v4 + with: + path: ~/.npm + key: ${{ runner.os }}-node-${{ matrix.node-version }}-npm-${{ hashFiles('package-lock.json') }} + restore-keys: | + ${{ runner.os }}-node-${{ matrix.node-version }}-npm- + + - name: Cache node_modules + id: node-modules-cache + uses: actions/cache@v4 + with: + path: node_modules + key: ${{ runner.os }}-node-${{ matrix.node-version }}-modules-${{ hashFiles('package-lock.json') }} + restore-keys: | + ${{ runner.os }}-node-${{ matrix.node-version }}-modules- + + - name: Install dependencies + if: steps.node-modules-cache.outputs.cache-hit != 'true' + run: npm ci + + - name: Run DM unit tests + run: npm run test:dm:unit + + dm-integration-tests: + runs-on: ubuntu-latest + strategy: + matrix: + node-version: [20] + + steps: + - name: Check out repository + uses: actions/checkout@v4 + + - name: Set up Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + + - name: Cache npm directory + uses: actions/cache@v4 + with: + path: ~/.npm + key: ${{ runner.os }}-node-${{ matrix.node-version }}-npm-${{ hashFiles('package-lock.json') }} + restore-keys: | + ${{ runner.os }}-node-${{ matrix.node-version }}-npm- + + - name: Cache node_modules + id: node-modules-cache + uses: actions/cache@v4 + with: + path: node_modules + key: ${{ runner.os }}-node-${{ matrix.node-version }}-modules-${{ hashFiles('package-lock.json') }} + restore-keys: | + ${{ runner.os }}-node-${{ matrix.node-version }}-modules- + + - name: Install dependencies + if: steps.node-modules-cache.outputs.cache-hit != 'true' + run: npm ci + + - name: Run DM integration tests + run: npm run test:dm:integration + + e2e-headless: + runs-on: ubuntu-latest + strategy: + matrix: + node-version: [20] + + steps: + - name: Check out repository + uses: actions/checkout@v4 + + - name: Set up Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + + - name: Cache npm directory + uses: actions/cache@v4 + with: + path: ~/.npm + key: ${{ runner.os }}-node-${{ matrix.node-version }}-npm-${{ hashFiles('package-lock.json') }} + restore-keys: | + ${{ runner.os }}-node-${{ matrix.node-version }}-npm- + + - name: Cache node_modules + id: node-modules-cache + uses: actions/cache@v4 + with: + path: node_modules + key: ${{ runner.os }}-node-${{ matrix.node-version }}-modules-${{ hashFiles('package-lock.json') }} + restore-keys: | + ${{ runner.os }}-node-${{ matrix.node-version }}-modules- + + - name: Install dependencies + if: steps.node-modules-cache.outputs.cache-hit != 'true' + run: npm ci + + - name: Install Playwright browsers + run: npx playwright install --with-deps chromium + + - name: Run headless E2E tests + run: npm run test:e2e diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9637fbde..9cc7cc55 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -36,6 +36,7 @@ If we later introduce **dual-licensing** options (e.g., commercial licenses for Automated agents contributing to this repository should follow these rules: - **Atomic Commits**: Keep changes small and self-contained. - **Descriptive Titles**: Use clear, semantic titles (e.g., `fix(ui): resolve upload modal overflow`). +- **Commit Messages**: Use the convention `type(scope): description (agent)` (e.g., `fix(ai): formatting (agent)` or `docs(ai): update quickstart (agent)`). - **Reference Issues**: Link to relevant issues in the PR description. - **Review AGENTS.md**: Always consult `AGENTS.md` for specific architectural guidelines and constraints before starting work. @@ -56,12 +57,17 @@ To set up the project locally: npm ci ``` -2. **Run Tests**: +2. **Build**: + ```bash + npm run build + ``` + +3. **Run Tests**: ```bash npm run test:unit ``` -3. **Format & Lint**: +4. **Format & Lint**: ```bash npm run format npm run lint @@ -69,6 +75,15 @@ To set up the project locally: For a full guide, see the [Local Setup section in README.md](./README.md#local-setup). +## Dev Container + +This project includes a `.devcontainer` configuration for VS Code. It provides a pre-configured environment with Node.js 22 and necessary extensions. + +To use it: +1. Open the project in VS Code. +2. When prompted, re-open in Container (or use the command palette: "Dev Containers: Reopen in Container"). +3. The container will automatically install dependencies and run the build. + ## Security If you find a vulnerability, please email **[security@bitvid.network](mailto:security@bitvid.network)**. We’ll coordinate a responsible disclosure window before public release. diff --git a/LINT_ISSUES.md b/LINT_ISSUES.md new file mode 100644 index 00000000..68701f53 --- /dev/null +++ b/LINT_ISSUES.md @@ -0,0 +1,20 @@ +# Lint Issues Report + +## Summary +Automated linting and formatting checks were run. No auto-fixable formatting issues were found. However, one linting error persists which requires manual intervention. + +## Issues + +### css/tailwind.source.css + +The `npm run lint:tokens` check failed with the following error: + +``` +css/tailwind.source.css:5757 → 767.98px + @media (max-width: 767.98px) { +``` + +**Recommendation:** +This raw measurement (`767.98px`) should be moved into `css/tokens.css` as a design token, or the linter configuration (`scripts/check-design-tokens.mjs`) should be updated to whitelist this specific value if it represents a standard responsive breakpoint for mobile layout fixes. + +Note: This error currently prevents `npm run lint` from completing successfully, meaning subsequent checks (`lint:tailwind-brackets`, `lint:tailwind-colors`) are skipped in the standard run script. These subsequent checks were run manually and passed. diff --git a/README.md b/README.md index 5de0cf26..9ca262ff 100644 --- a/README.md +++ b/README.md @@ -107,7 +107,13 @@ To run **bitvid** locally: npm ci ``` -3. Start a local server: +3. Build the project: + + ```bash + npm run build + ``` + +4. Start a local server: - Using Python: ```bash python -m http.server 8000 @@ -117,17 +123,20 @@ To run **bitvid** locally: npx serve ``` -4. Open the site in your browser: +5. Open the site in your browser: ``` http://localhost:8000 ``` -### Common Commands +### Quickstart Commands - **Run unit tests**: `npm run test:unit` - **Format code**: `npm run format` - **Lint code**: `npm run lint` +- **Run DM unit tests**: `npm run test:dm:unit` +- **Run DM integration tests**: `npm run test:dm:integration` +- **Run headless E2E tests**: `npm run test:e2e` ### Send your first video post @@ -137,13 +146,14 @@ Use the event builders in `js/nostrEventSchemas.js` to construct valid video not import { buildVideoPostEvent } from "./js/nostrEventSchemas.js"; const event = buildVideoPostEvent({ + // Provide your hex pubkey (not npub) pubkey: "your_pubkey_hex", created_at: Math.floor(Date.now() / 1000), - dTagValue: "my-first-video", + dTagValue: "my-first-video", // The stable identifier (d-tag) for this video content: { version: 3, title: "My First Video", - videoRootId: "my-first-video", // Logical ID, often matches d-tag + videoRootId: "my-first-video", // Logical ID, typically matches the d-tag url: "https://example.com/video.mp4", description: "This is a test video post sent via the SDK." // magnet: "magnet:?xt=urn:btih:..." // Optional fallback @@ -393,10 +403,13 @@ placeholder at “—” and development builds log a warning—so mixed deploym ## Testing -Continuous integration runs CSS linting/builds, the Playwright kitchen-sink snapshots, and the Node-based unit tests on every push. +Continuous integration runs CSS linting/builds, the DM unit/integration suites, the Playwright kitchen-sink snapshots, headless E2E flows, and the Node-based unit tests on every push. Before pushing, run `npm run build` locally so the Tailwind bundle regenerates. Pair that with `npm run test:unit` for application logic changes and `npm run test:visual` for presentation updates to mirror the CI surface area. +For DM-specific changes, also run `npm run test:dm:unit` and +`npm run test:dm:integration` to cover the direct message flows. +Use `npm run test:e2e` to execute the headless Playwright journeys in `tests/e2e`. ### Manual QA checklist diff --git a/artifacts/npm-audit.json b/artifacts/npm-audit.json new file mode 100644 index 00000000..223b4829 --- /dev/null +++ b/artifacts/npm-audit.json @@ -0,0 +1,22 @@ +{ + "auditReportVersion": 2, + "vulnerabilities": {}, + "metadata": { + "vulnerabilities": { + "info": 0, + "low": 0, + "moderate": 0, + "high": 0, + "critical": 0, + "total": 0 + }, + "dependencies": { + "prod": 5, + "dev": 316, + "optional": 29, + "peer": 8, + "peerOptional": 0, + "total": 320 + } + } +} diff --git a/artifacts/npm-outdated.json b/artifacts/npm-outdated.json new file mode 100644 index 00000000..9c6c6246 --- /dev/null +++ b/artifacts/npm-outdated.json @@ -0,0 +1,58 @@ +{ + "cross-env": { + "current": "7.0.3", + "wanted": "7.0.3", + "latest": "10.1.0", + "dependent": "app", + "location": "/app/node_modules/cross-env" + }, + "esbuild": { + "current": "0.25.12", + "wanted": "0.25.12", + "latest": "0.27.2", + "dependent": "app", + "location": "/app/node_modules/esbuild" + }, + "jsdom": { + "current": "24.1.3", + "wanted": "24.1.3", + "latest": "27.4.0", + "dependent": "app", + "location": "/app/node_modules/jsdom" + }, + "pixelmatch": { + "current": "5.3.0", + "wanted": "5.3.0", + "latest": "7.1.0", + "dependent": "app", + "location": "/app/node_modules/pixelmatch" + }, + "prettier-plugin-tailwindcss": { + "current": "0.6.14", + "wanted": "0.6.14", + "latest": "0.7.2", + "dependent": "app", + "location": "/app/node_modules/prettier-plugin-tailwindcss" + }, + "stylelint": { + "current": "16.26.1", + "wanted": "16.26.1", + "latest": "17.0.0", + "dependent": "app", + "location": "/app/node_modules/stylelint" + }, + "stylelint-config-standard": { + "current": "36.0.1", + "wanted": "36.0.1", + "latest": "40.0.0", + "dependent": "app", + "location": "/app/node_modules/stylelint-config-standard" + }, + "tailwindcss": { + "current": "3.4.19", + "wanted": "3.4.19", + "latest": "4.1.18", + "dependent": "app", + "location": "/app/node_modules/tailwindcss" + } +} diff --git a/components/disclaimer.html b/components/disclaimer.html index 9e952106..80910136 100644 --- a/components/disclaimer.html +++ b/components/disclaimer.html @@ -1,7 +1,7 @@ -