diff --git a/artifacts/deps-report.md b/artifacts/deps-report.md index 38ebfd87..a169cf56 100644 --- a/artifacts/deps-report.md +++ b/artifacts/deps-report.md @@ -1,26 +1,28 @@ -# Dependency Security Report: 2026-02-14 +# Dependency Audit Report -## Summary -- **Vulnerabilities**: 0 -- **Outdated Packages**: 7 -- **Critical/High Issues**: 0 +## 1. Vulnerability Summary +- Total Vulnerabilities: 0 +- Critical: 0 +- High: 0 +- Moderate: 0 +- Low: 0 -## Vulnerabilities -No known vulnerabilities found. +No vulnerabilities found. -## Outdated Packages +## 2. Outdated Packages +### Safe Upgrades (Patch/Minor) +- **jsdom** (dependencies): 28.0.0 -> 28.1.0 (Latest: 28.1.0) +- **stylelint** (dependencies): 16.12.0 -> 16.26.1 (Latest: 17.3.0) -| Package | Current | Wanted | Latest | Type | Status | -|---------|---------|--------|--------|------|--------| -| `nostr-tools` | 2.19.4 | 2.23.1 | 2.23.1 | dep | **REQUIRES REVIEW** (Crypto) | -| `stylelint` | 16.12.0 | 16.26.1 | 17.3.0 | devDep | Safe Candidate | -| `pixelmatch` | 5.3.0 | 5.3.0 | 7.1.0 | devDep | Major | -| `postcss-import` | 15.1.0 | 15.1.0 | 16.1.1 | devDep | Major | -| `prettier-plugin-tailwindcss` | 0.6.14 | 0.6.14 | 0.7.2 | devDep | Major/Minor | -| `stylelint-config-standard` | 36.0.1 | 36.0.1 | 40.0.0 | devDep | Major | -| `tailwindcss` | 3.4.19 | 3.4.19 | 4.1.18 | devDep | Major | +### Major Upgrades (Risky) +- **pixelmatch** (dependencies): 5.3.0 -> 7.1.0 +- **postcss-import** (dependencies): 15.1.0 -> 16.1.1 +- **prettier-plugin-tailwindcss** (dependencies): 0.6.14 -> 0.7.2 +- **stylelint-config-standard** (dependencies): 36.0.1 -> 40.0.0 +- **tailwindcss** (dependencies): 3.4.19 -> 4.1.18 -## Recommendations -1. **nostr-tools**: Open an issue to review the changes in 2.23.1 and verify NIP compatibility. -2. **stylelint**: Safe to upgrade to 16.26.1. -3. **tailwindcss**: Plan migration to v4. +### Security/Protocol Libraries (Manual Review Required) +- **nostr-tools** (dependencies): 2.19.4 -> 2.23.1 (Latest: 2.23.1) + +## 3. Recommendations +- **Action Item**: Attempt safe upgrade of `jsdom` from `28.0.0` to `28.1.0`. diff --git a/artifacts/npm-outdated.json b/artifacts/npm-outdated.json index d46967a8..cb98705b 100644 --- a/artifacts/npm-outdated.json +++ b/artifacts/npm-outdated.json @@ -1,4 +1,11 @@ { + "jsdom": { + "current": "28.0.0", + "wanted": "28.1.0", + "latest": "28.1.0", + "dependent": "app", + "location": "/app/node_modules/jsdom" + }, "nostr-tools": { "current": "2.19.4", "wanted": "2.23.1", diff --git a/context/CONTEXT_2026-02-16.md b/context/CONTEXT_2026-02-16.md new file mode 100644 index 00000000..eba42f24 --- /dev/null +++ b/context/CONTEXT_2026-02-16.md @@ -0,0 +1 @@ +# Context for 2026-02-16 diff --git a/decisions/DECISIONS_2026-02-16.md b/decisions/DECISIONS_2026-02-16.md index 445cda77..db0d2a51 100644 --- a/decisions/DECISIONS_2026-02-16.md +++ b/decisions/DECISIONS_2026-02-16.md @@ -11,3 +11,6 @@ - Chosen canonical constant: `MAX_BLOCKLIST_ENTRIES` - Location: `js/constants.js` - Reason: `MAX_BLOCKLIST_ENTRIES` was defined locally in `js/userBlocks.js`. Extracted to `js/constants.js` to centralize limits. + +## 2026-02-16 - deps-security-agent +- **jsdom**: Upgraded to `28.1.0` (Safe patch/minor upgrade verified by tests). diff --git a/docs/agents/task-logs/daily/2026-02-16_12-50-07_deps-security-agent_completed.md b/docs/agents/task-logs/daily/2026-02-16_12-50-07_deps-security-agent_completed.md new file mode 100644 index 00000000..d39f09b9 --- /dev/null +++ b/docs/agents/task-logs/daily/2026-02-16_12-50-07_deps-security-agent_completed.md @@ -0,0 +1,16 @@ +# deps-security-agent Report + +## Summary +Performed daily dependency audit. Generated artifacts in `artifacts/`. + +## Upgrades +- **jsdom**: Upgraded from `28.0.0` to `28.1.0` (Safe patch/minor upgrade). +- Verified with `npm run test:unit:shard[1-3]`. + +## Artifacts +- `artifacts/npm-audit.json` +- `artifacts/npm-outdated.json` +- `artifacts/deps-report.md` + +## Next Steps +- Review `artifacts/deps-report.md` for other potential upgrades. diff --git a/package-lock.json b/package-lock.json index 1b7dca99..4259fcd9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,7 +23,7 @@ "@playwright/test": "^1.58.2", "cssnano": "^7.1.2", "fake-indexeddb": "^6.2.5", - "jsdom": "^28.0.0", + "jsdom": "^28.1.0", "nostr-wasm": "^0.1.0", "pixelmatch": "^5.3.0", "playwright": "^1.58.2", @@ -61,23 +61,118 @@ } }, "node_modules/@asamuzakjp/css-color": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-4.1.1.tgz", - "integrity": "sha512-B0Hv6G3gWGMn0xKJ0txEi/jM5iFpT3MfDxmhZFb4W047GvytCf1DHQ1D69W3zHI4yWe2aTZAA0JnbMZ7Xc8DuQ==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-4.1.2.tgz", + "integrity": "sha512-NfBUvBaYgKIuq6E/RBLY1m0IohzNHAYyaJGuTK79Z23uNwmz2jl1mPsC5ZxCCxylinKhT1Amn5oNTlx1wN8cQg==", "dev": true, "license": "MIT", "dependencies": { - "@csstools/css-calc": "^2.1.4", - "@csstools/css-color-parser": "^3.1.0", - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4", - "lru-cache": "^11.2.4" + "@csstools/css-calc": "^3.0.0", + "@csstools/css-color-parser": "^4.0.1", + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0", + "lru-cache": "^11.2.5" + } + }, + "node_modules/@asamuzakjp/css-color/node_modules/@csstools/css-calc": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-3.1.1.tgz", + "integrity": "sha512-HJ26Z/vmsZQqs/o3a6bgKslXGFAungXGbinULZO3eMsOyNJHeBBZfup5FiZInOghgoM4Hwnmw+OgbJCNg1wwUQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0" + } + }, + "node_modules/@asamuzakjp/css-color/node_modules/@csstools/css-color-parser": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-4.0.1.tgz", + "integrity": "sha512-vYwO15eRBEkeF6xjAno/KQ61HacNhfQuuU/eGwH67DplL0zD5ZixUa563phQvUelA07yDczIXdtmYojCphKJcw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "@csstools/color-helpers": "^6.0.1", + "@csstools/css-calc": "^3.0.0" + }, + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0" + } + }, + "node_modules/@asamuzakjp/css-color/node_modules/@csstools/css-parser-algorithms": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-4.0.0.tgz", + "integrity": "sha512-+B87qS7fIG3L5h3qwJ/IFbjoVoOe/bpOdh9hAjXbvx0o8ImEmUsGXN0inFOnk2ChCFgqkkGFQ+TpM5rbhkKe4w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "@csstools/css-tokenizer": "^4.0.0" + } + }, + "node_modules/@asamuzakjp/css-color/node_modules/@csstools/css-tokenizer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-4.0.0.tgz", + "integrity": "sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=20.19.0" } }, "node_modules/@asamuzakjp/dom-selector": { - "version": "6.7.7", - "resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-6.7.7.tgz", - "integrity": "sha512-8CO/UQ4tzDd7ula+/CVimJIVWez99UJlbMyIgk8xOnhAVPKLnBZmUFYVgugS441v2ZqUq5EnSh6B0Ua0liSFAA==", + "version": "6.8.1", + "resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-6.8.1.tgz", + "integrity": "sha512-MvRz1nCqW0fsy8Qz4dnLIvhOlMzqDVBabZx6lH+YywFDdjXhMY37SmpV1XFX3JzG5GWHn63j6HX6QPr3lZXHvQ==", "dev": true, "license": "MIT", "dependencies": { @@ -85,7 +180,7 @@ "bidi-js": "^1.0.3", "css-tree": "^3.1.0", "is-potential-custom-element-name": "^1.0.1", - "lru-cache": "^11.2.5" + "lru-cache": "^11.2.6" } }, "node_modules/@asamuzakjp/nwsapi": { @@ -120,10 +215,23 @@ "node": ">=6.9.0" } }, + "node_modules/@bramus/specificity": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@bramus/specificity/-/specificity-2.4.2.tgz", + "integrity": "sha512-ctxtJ/eA+t+6q2++vj5j7FYX3nRu311q1wfYH3xjlLOsczhlhxAg2FWNUXhpGvAw3BWo1xBcvOV6/YLc2r5FJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "css-tree": "^3.0.0" + }, + "bin": { + "specificity": "bin/cli.js" + } + }, "node_modules/@csstools/color-helpers": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.1.0.tgz", - "integrity": "sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-6.0.1.tgz", + "integrity": "sha512-NmXRccUJMk2AWA5A7e5a//3bCIMyOu2hAtdRYrhPPHjDxINuCwX1w6rnIZ4xjLcp0ayv6h8Pc3X0eJUGiAAXHQ==", "dev": true, "funding": [ { @@ -137,59 +245,7 @@ ], "license": "MIT-0", "engines": { - "node": ">=18" - } - }, - "node_modules/@csstools/css-calc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.1.4.tgz", - "integrity": "sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT", - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4" - } - }, - "node_modules/@csstools/css-color-parser": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.1.0.tgz", - "integrity": "sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT", - "dependencies": { - "@csstools/color-helpers": "^5.1.0", - "@csstools/css-calc": "^2.1.4" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4" + "node": ">=20.19.0" } }, "node_modules/@csstools/css-parser-algorithms": { @@ -216,9 +272,9 @@ } }, "node_modules/@csstools/css-syntax-patches-for-csstree": { - "version": "1.0.26", - "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.0.26.tgz", - "integrity": "sha512-6boXK0KkzT5u5xOgF6TKB+CLq9SOpEGmkZw0g5n9/7yg85wab3UzSxB8TxhLJ31L4SGJ6BCFRw/iftTha1CJXA==", + "version": "1.0.27", + "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.0.27.tgz", + "integrity": "sha512-sxP33Jwg1bviSUXAV43cVYdmjt2TLnLXNqCWl9xmxHawWVjGz/kEbdkr7F9pxJNBN2Mh+dq0crgItbW6tQvyow==", "dev": true, "funding": [ { @@ -2419,16 +2475,16 @@ "license": "CC0-1.0" }, "node_modules/cssstyle": { - "version": "5.3.7", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-5.3.7.tgz", - "integrity": "sha512-7D2EPVltRrsTkhpQmksIu+LxeWAIEk6wRDMJ1qljlv+CKHJM+cJLlfhWIzNA44eAsHXSNe3+vO6DW1yCYx8SuQ==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-6.0.1.tgz", + "integrity": "sha512-IoJs7La+oFp/AB033wBStxNOJt4+9hHMxsXUPANcoXL2b3W4DZKghlJ2cI/eyeRZIQ9ysvYEorVhjrcYctWbog==", "dev": true, "license": "MIT", "dependencies": { - "@asamuzakjp/css-color": "^4.1.1", - "@csstools/css-syntax-patches-for-csstree": "^1.0.21", + "@asamuzakjp/css-color": "^4.1.2", + "@csstools/css-syntax-patches-for-csstree": "^1.0.26", "css-tree": "^3.1.0", - "lru-cache": "^11.2.4" + "lru-cache": "^11.2.5" }, "engines": { "node": ">=20" @@ -3336,16 +3392,17 @@ } }, "node_modules/jsdom": { - "version": "28.0.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-28.0.0.tgz", - "integrity": "sha512-KDYJgZ6T2TKdU8yBfYueq5EPG/EylMsBvCaenWMJb2OXmjgczzwveRCoJ+Hgj1lXPDyasvrgneSn4GBuR1hYyA==", + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-28.1.0.tgz", + "integrity": "sha512-0+MoQNYyr2rBHqO1xilltfDjV9G7ymYGlAUazgcDLQaUf8JDHbuGwsxN6U9qWaElZ4w1B2r7yEGIL3GdeW3Rug==", "dev": true, "license": "MIT", "dependencies": { "@acemir/cssom": "^0.9.31", - "@asamuzakjp/dom-selector": "^6.7.6", + "@asamuzakjp/dom-selector": "^6.8.1", + "@bramus/specificity": "^2.4.2", "@exodus/bytes": "^1.11.0", - "cssstyle": "^5.3.7", + "cssstyle": "^6.0.1", "data-urls": "^7.0.0", "decimal.js": "^10.6.0", "html-encoding-sniffer": "^6.0.0", @@ -3356,7 +3413,7 @@ "saxes": "^6.0.0", "symbol-tree": "^3.2.4", "tough-cookie": "^6.0.0", - "undici": "^7.20.0", + "undici": "^7.21.0", "w3c-xmlserializer": "^5.0.0", "webidl-conversions": "^8.0.1", "whatwg-mimetype": "^5.0.0", @@ -3476,9 +3533,9 @@ "license": "MIT" }, "node_modules/lru-cache": { - "version": "11.2.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.5.tgz", - "integrity": "sha512-vFrFJkWtJvJnD5hg+hJvVE8Lh/TcMzKnTgCWmtBipwI5yLX/iX+5UB2tfuyODF5E7k9xEzMdYgGqaSb1c0c5Yw==", + "version": "11.2.6", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.6.tgz", + "integrity": "sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==", "dev": true, "license": "BlueOak-1.0.0", "engines": { @@ -6065,9 +6122,9 @@ } }, "node_modules/undici": { - "version": "7.20.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-7.20.0.tgz", - "integrity": "sha512-MJZrkjyd7DeC+uPZh+5/YaMDxFiiEEaDgbUSVMXayofAkDWF1088CDo+2RPg7B1BuS1qf1vgNE7xqwPxE0DuSQ==", + "version": "7.22.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.22.0.tgz", + "integrity": "sha512-RqslV2Us5BrllB+JeiZnK4peryVTndy9Dnqq62S3yYRRTj0tFQCwEniUy2167skdGOy3vqRzEvl1Dm4sV2ReDg==", "dev": true, "license": "MIT", "engines": { diff --git a/package.json b/package.json index 48259988..e22fe8fd 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "@playwright/test": "^1.58.2", "cssnano": "^7.1.2", "fake-indexeddb": "^6.2.5", - "jsdom": "^28.0.0", + "jsdom": "^28.1.0", "nostr-wasm": "^0.1.0", "pixelmatch": "^5.3.0", "playwright": "^1.58.2", diff --git a/test_logs/TEST_LOG_2026-02-16.md b/test_logs/TEST_LOG_2026-02-16.md new file mode 100644 index 00000000..e289d484 --- /dev/null +++ b/test_logs/TEST_LOG_2026-02-16.md @@ -0,0 +1,10886 @@ +# Test Logs for 2026-02-16 +Running npm ci... + +> bitvid@1.0.0 prepare +> npm run build:css + + +> bitvid@1.0.0 build:css +> postcss css/tailwind.source.css -o css/tailwind.generated.css + + +added 424 packages, and audited 425 packages in 19s + +108 packages are looking for funding + run `npm fund` for details + +found 0 vulnerabilities + +added 5 packages, removed 2 packages, changed 8 packages, and audited 428 packages in 4s + +110 packages are looking for funding + run `npm fund` for details + +found 0 vulnerabilities + +> bitvid@1.0.0 test:unit +> node scripts/run-unit-tests.mjs + + +→ Running tests/app-batch-fetch-profiles.test.mjs +TAP version 13 +# Subtest: batchFetchProfiles handles fast and failing relays +ok 1 - batchFetchProfiles handles fast and failing relays + --- + duration_ms: 4.01842 + type: 'test' + ... +# Subtest: batchFetchProfiles respects forceRefresh +ok 2 - batchFetchProfiles respects forceRefresh + --- + duration_ms: 0.966896 + type: 'test' + ... +1..2 +# tests 2 +# suites 0 +# pass 2 +# fail 0 +# cancelled 0 +# skipped 0 +# todo 0 +# duration_ms 16.781695 + +→ Running tests/app-state.test.mjs +TAP version 13 +# Subtest: AppState + # Subtest: Initial state is clean + ok 1 - Initial state is clean + --- + duration_ms: 2.637879 + type: 'test' + ... + # Subtest: setPubkey() updates state and notifies subscribers + ok 2 - setPubkey() updates state and notifies subscribers + --- + duration_ms: 1.084388 + type: 'test' + ... + # Subtest: setCurrentUserNpub() updates state + ok 3 - setCurrentUserNpub() updates state + --- + duration_ms: 0.507429 + type: 'test' + ... + # Subtest: setCurrentVideo() updates state + ok 4 - setCurrentVideo() updates state + --- + duration_ms: 0.571966 + type: 'test' + ... + # Subtest: setVideosMap() updates state + ok 5 - setVideosMap() updates state + --- + duration_ms: 1.06145 + type: 'test' + ... + # Subtest: setVideoSubscription() updates state + ok 6 - setVideoSubscription() updates state + --- + duration_ms: 0.578872 + type: 'test' + ... + # Subtest: setModalState() updates state and notifies modal subscribers + ok 7 - setModalState() updates state and notifies modal subscribers + --- + duration_ms: 0.979166 + type: 'test' + ... + # Subtest: Global subscriber receives updates + ok 8 - Global subscriber receives updates + --- + duration_ms: 0.68527 + type: 'test' + ... + # Subtest: resetAppState() clears all state and notifies + ok 9 - resetAppState() clears all state and notifies + --- + duration_ms: 1.22186 + type: 'test' + ... + 1..9 +ok 1 - AppState + --- + duration_ms: 11.900583 + type: 'suite' + ... +1..1 +# tests 9 +# suites 1 +# pass 9 +# fail 0 +# cancelled 0 +# skipped 0 +# todo 0 +# duration_ms 34.748088 + +→ Running tests/app/channel-profile-moderation.test.mjs +TAP version 13 +# Subtest: renderChannelVideosFromList decorates videos before storing +ok 1 - renderChannelVideosFromList decorates videos before storing + --- + duration_ms: 147.202064 + type: 'test' + ... +# Subtest: renderChannelVideosFromList applies moderation blur without existing metadata +ok 2 - renderChannelVideosFromList applies moderation blur without existing metadata + --- + duration_ms: 45.476705 + type: 'test' + ... +# Subtest: applyChannelVisualBlur blurs banner and avatar when viewer mutes author +ok 3 - applyChannelVisualBlur blurs banner and avatar when viewer mutes author + --- + duration_ms: 14.982635 + type: 'test' + ... +# Subtest: moderation override clears channel blur via event wiring +ok 4 - moderation override clears channel blur via event wiring + --- + duration_ms: 32.561716 + type: 'test' + ... +# Subtest: channel header moderation badge reflects blur state and override actions +ok 5 - channel header moderation badge reflects blur state and override actions + --- + duration_ms: 28.986907 + type: 'test' + ... +# Subtest: channel video cards update moderation state in place when summary changes +ok 6 - channel video cards update moderation state in place when summary changes + --- + duration_ms: 31.604459 + type: 'test' + ... +1..6 +# tests 6 +# suites 0 +# pass 6 +# fail 0 +# cancelled 0 +# skipped 0 +# todo 0 +# duration_ms 318.379292 + +→ Running tests/app/feedCoordinator.test.mjs +TAP version 13 +# Subtest: createFeedCoordinator - loadForYouVideos + # Subtest: loadForYouVideos executes successfully + ok 1 - loadForYouVideos executes successfully + --- + duration_ms: 2.55215 + type: 'test' + ... + 1..1 +ok 1 - createFeedCoordinator - loadForYouVideos + --- + duration_ms: 4.538199 + type: 'test' + ... +1..1 +# tests 2 +# suites 0 +# pass 2 +# fail 0 +# cancelled 0 +# skipped 0 +# todo 0 +# duration_ms 15.983581 + +→ Running tests/app/hash-change-handler.test.mjs +TAP version 13 +# Subtest: handleHashChange defaults to for-you when logged in +ok 1 - handleHashChange defaults to for-you when logged in + --- + duration_ms: 90.025969 + type: 'test' + ... +# Subtest: handleHashChange defaults to most-recent-videos when logged out +ok 2 - handleHashChange defaults to most-recent-videos when logged out + --- + duration_ms: 13.859391 + type: 'test' + ... +# Subtest: handleHashChange respects explicit view regardless of login state +ok 3 - handleHashChange respects explicit view regardless of login state + --- + duration_ms: 13.346437 + type: 'test' + ... +1..3 +# tests 3 +# suites 0 +# pass 3 +# fail 0 +# cancelled 0 +# skipped 0 +# todo 0 +# duration_ms 132.224508 + +→ Running tests/app/hydrate-sidebar-navigation.test.mjs +TAP version 13 +# Subtest: hydrateSidebarNavigation reveals chrome controls for authenticated viewers +ok 1 - hydrateSidebarNavigation reveals chrome controls for authenticated viewers + --- + duration_ms: 96.263846 + type: 'test' + ... +# Subtest: hydrateSidebarNavigation hides chrome controls for logged-out viewers +ok 2 - hydrateSidebarNavigation hides chrome controls for logged-out viewers + --- + duration_ms: 14.563337 + type: 'test' + ... +1..2 +# tests 2 +# suites 0 +# pass 2 +# fail 0 +# cancelled 0 +# skipped 0 +# todo 0 +# duration_ms 123.002063 + +→ Running tests/app/is-user-logged-in.test.mjs +TAP version 13 +# Subtest: isUserLoggedIn returns false when no user pubkey is set +ok 1 - isUserLoggedIn returns false when no user pubkey is set + --- + duration_ms: 1.358487 + type: 'test' + ... +# Subtest: isUserLoggedIn treats extension logins as authenticated +ok 2 - isUserLoggedIn treats extension logins as authenticated + --- + duration_ms: 0.338155 + type: 'test' + ... +# Subtest: isUserLoggedIn guards against mismatched nostrClient state +ok 3 - isUserLoggedIn guards against mismatched nostrClient state + --- + duration_ms: 0.210792 + type: 'test' + ... +# Subtest: isUserLoggedIn ignores anonymous session actor mismatches +ok 4 - isUserLoggedIn ignores anonymous session actor mismatches + --- + duration_ms: 0.269272 + type: 'test' + ... +# Subtest: isUserLoggedIn rejects mismatched managed session actors +ok 5 - isUserLoggedIn rejects mismatched managed session actors + --- + duration_ms: 0.587834 + type: 'test' + ... +1..5 +# tests 5 +# suites 0 +# pass 5 +# fail 0 +# cancelled 0 +# skipped 0 +# todo 0 +# duration_ms 31.142902 + +→ Running tests/app/moderation-overrides.test.mjs +TAP version 13 +# Subtest: handleModerationOverride decorates stored and current videos then refreshes UI +ok 1 - handleModerationOverride decorates stored and current videos then refreshes UI + --- + duration_ms: 6.005706 + type: 'test' + ... +# Subtest: handleModerationOverride resumes deferred playback +ok 2 - handleModerationOverride resumes deferred playback + --- + duration_ms: 1.244395 + type: 'test' + ... +# Subtest: handleModerationBlock requests a block, clears overrides, and refreshes hidden state +ok 3 - handleModerationBlock requests a block, clears overrides, and refreshes hidden state + --- + duration_ms: 3.720907 + type: 'test' + ... +# Subtest: handleModerationBlock returns false when viewer is logged out +ok 4 - handleModerationBlock returns false when viewer is logged out + --- + duration_ms: 1.011935 + type: 'test' + ... +1..4 +# tests 4 +# suites 0 +# pass 4 +# fail 0 +# cancelled 0 +# skipped 0 +# todo 0 +# duration_ms 28.129108 + +→ Running tests/app/moderation-settings-refresh.test.mjs +TAP version 13 +# Subtest: handleModerationSettingsChange refreshes feeds with updated thresholds +ok 1 - handleModerationSettingsChange refreshes feeds with updated thresholds + --- + duration_ms: 4.545188 + type: 'test' + ... +1..1 +# tests 1 +# suites 0 +# pass 1 +# fail 0 +# cancelled 0 +# skipped 0 +# todo 0 +# duration_ms 16.323418 + +→ Running tests/app/similar-content.test.mjs +TAP version 13 +# Subtest: orders similar videos by shared tags then timestamp +ok 1 - orders similar videos by shared tags then timestamp + --- + duration_ms: 3.44956 + type: 'test' + ... +# Subtest: returns no matches when the active video lacks tags +ok 2 - returns no matches when the active video lacks tags + --- + duration_ms: 0.596169 + type: 'test' + ... +# Subtest: skips candidates without tag metadata +ok 3 - skips candidates without tag metadata + --- + duration_ms: 0.365263 + type: 'test' + ... +# Subtest: filters NSFW and private videos when NSFW content is disabled +ok 4 - filters NSFW and private videos when NSFW content is disabled + --- + duration_ms: 0.604417 + type: 'test' + ... +1..4 +# tests 4 +# suites 0 +# pass 4 +# fail 0 +# cancelled 0 +# skipped 0 +# todo 0 +# duration_ms 17.501604 + +→ Running tests/auth-service.test.mjs +TAP version 13 +# Subtest: AuthService + # Subtest: applyPostLoginState success flow + ok 1 - applyPostLoginState success flow + --- + duration_ms: 14.515251 + type: 'test' + ... + # Subtest: applyPostLoginState with deferBlocks: true + ok 2 - applyPostLoginState with deferBlocks: true + --- + duration_ms: 10.738254 + type: 'test' + ... + # Subtest: applyPostLoginState partial failure + ok 3 - applyPostLoginState partial failure + --- + duration_ms: 1.601171 + type: 'test' + ... + # Subtest: applyPostLoginState without pubkey + ok 4 - applyPostLoginState without pubkey + --- + duration_ms: 0.705631 + type: 'test' + ... + # Subtest: login mocks postLogin flow + ok 5 - login mocks postLogin flow + --- + duration_ms: 3.151055 + type: 'test' + ... + # Subtest: login fails on lockdown + ok 6 - login fails on lockdown + --- + duration_ms: 1.029846 + type: 'test' + ... + # Subtest: login succeeds for admin on lockdown + ok 7 - login succeeds for admin on lockdown + --- + duration_ms: 1.369958 + type: 'test' + ... + # Subtest: loadOwnProfile + # Subtest: Fast Relay Success + ok 1 - Fast Relay Success + --- + duration_ms: 1.325011 + type: 'test' + ... + # Subtest: All Relays Fail + ok 2 - All Relays Fail + --- + duration_ms: 1.279888 + type: 'test' + ... + # Subtest: Timeout Fallback + ok 3 - Timeout Fallback + --- + duration_ms: 2502.454327 + type: 'test' + ... + 1..3 + ok 8 - loadOwnProfile + --- + duration_ms: 2505.86568 + type: 'suite' + ... + 1..8 +ok 1 - AuthService + --- + duration_ms: 2540.985359 + type: 'suite' + ... +1..1 +# tests 10 +# suites 2 +# pass 10 +# fail 0 +# cancelled 0 +# skipped 0 +# todo 0 +# duration_ms 2549.52559 + +→ Running tests/auth/signingAdapter.test.mjs +TAP version 13 +# Subtest: createNip07SigningAdapter + # Subtest: uses explicit extension if provided + ok 1 - uses explicit extension if provided + --- + duration_ms: 3.757185 + type: 'test' + ... + # Subtest: falls back to window.nostr if no extension provided + ok 2 - falls back to window.nostr if no extension provided + --- + duration_ms: 0.643923 + type: 'test' + ... + # Subtest: throws error if no extension available + ok 3 - throws error if no extension available + --- + duration_ms: 1.326058 + type: 'test' + ... + # Subtest: prioritizes explicit extension over window.nostr + ok 4 - prioritizes explicit extension over window.nostr + --- + duration_ms: 0.836377 + type: 'test' + ... + 1..4 +ok 1 - createNip07SigningAdapter + --- + duration_ms: 8.262425 + type: 'suite' + ... +1..1 +# tests 4 +# suites 1 +# pass 4 +# fail 0 +# cancelled 0 +# skipped 0 +# todo 0 +# duration_ms 21.563094 + +→ Running tests/authService.test.mjs +TAP version 13 +# Subtest: AuthService Coverage + # Subtest: login + # Subtest: successfully logs in with valid pubkey + ok 1 - successfully logs in with valid pubkey + --- + duration_ms: 6.886312 + type: 'test' + ... + # Subtest: updates global state and calls post-login hooks + ok 2 - updates global state and calls post-login hooks + --- + duration_ms: 1.52451 + type: 'test' + ... + # Subtest: throws if lockdown is active and user is not admin + ok 3 - throws if lockdown is active and user is not admin + --- + duration_ms: 1.848597 + type: 'test' + ... + # Subtest: allows login if lockdown is active but user is admin + ok 4 - allows login if lockdown is active but user is admin + --- + duration_ms: 1.181426 + type: 'test' + ... + 1..4 + ok 1 - login + --- + duration_ms: 13.042229 + type: 'suite' + ... + # Subtest: logout + # Subtest: clears state and calls reset on dependencies + ok 1 - clears state and calls reset on dependencies + --- + duration_ms: 2.140077 + type: 'test' + ... + 1..1 + ok 2 - logout + --- + duration_ms: 2.571073 + type: 'suite' + ... + # Subtest: requestLogin + # Subtest: uses provider to login + ok 1 - uses provider to login + --- + duration_ms: 1.315193 + type: 'test' + ... + # Subtest: does not call login if autoApply is false + ok 2 - does not call login if autoApply is false + --- + duration_ms: 0.802439 + type: 'test' + ... + 1..2 + ok 3 - requestLogin + --- + duration_ms: 2.422675 + type: 'suite' + ... + # Subtest: switchProfile + # Subtest: switches to an existing profile + ok 1 - switches to an existing profile + --- + duration_ms: 3.463541 + type: 'test' + ... + # Subtest: reorders saved profiles on switch + ok 2 - reorders saved profiles on switch + --- + duration_ms: 2.499656 + type: 'test' + ... + 1..2 + ok 4 - switchProfile + --- + duration_ms: 6.205295 + type: 'suite' + ... + 1..4 +ok 1 - AuthService Coverage + --- + duration_ms: 25.498607 + type: 'suite' + ... +1..1 +# tests 9 +# suites 5 +# pass 9 +# fail 0 +# cancelled 0 +# skipped 0 +# todo 0 +# duration_ms 43.799416 + +→ Running tests/comment-event-builder.test.mjs +TAP version 13 +# Subtest: buildCommentEvent emits NIP-22 root metadata while keeping legacy fallbacks +ok 1 - buildCommentEvent emits NIP-22 root metadata while keeping legacy fallbacks + --- + duration_ms: 3.044692 + type: 'test' + ... +# Subtest: buildCommentEvent includes parent pointers, kinds, and authors for replies +ok 2 - buildCommentEvent includes parent pointers, kinds, and authors for replies + --- + duration_ms: 0.493314 + type: 'test' + ... +# Subtest: buildCommentEvent normalizes relays and preserves explicit overrides +ok 3 - buildCommentEvent normalizes relays and preserves explicit overrides + --- + duration_ms: 0.813665 + type: 'test' + ... +# Subtest: buildCommentEvent falls back to event pointers when no address is supplied +ok 4 - buildCommentEvent falls back to event pointers when no address is supplied + --- + duration_ms: 0.281288 + type: 'test' + ... +# Subtest: buildCommentEvent accepts partial metadata for parent overrides +ok 5 - buildCommentEvent accepts partial metadata for parent overrides + --- + duration_ms: 0.424866 + type: 'test' + ... +# Subtest: buildCommentEvent sanitizes additional tags before signing +ok 6 - buildCommentEvent sanitizes additional tags before signing + --- + duration_ms: 0.977509 + type: 'test' + ... +1..6 +# tests 6 +# suites 0 +# pass 6 +# fail 0 +# cancelled 0 +# skipped 0 +# todo 0 +# duration_ms 20.480125 + +→ Running tests/comment-thread-service.test.mjs +TAP version 13 +# Subtest: CommentThreadService caches mixed-case video ids consistently +ok 1 - CommentThreadService caches mixed-case video ids consistently + --- + duration_ms: 3.451471 + type: 'test' + ... +# Subtest: CommentThreadService surfaces cache read failures +ok 2 - CommentThreadService surfaces cache read failures + --- + duration_ms: 0.773296 + type: 'test' + ... +# Subtest: CommentThreadService surfaces cache write failures +ok 3 - CommentThreadService surfaces cache write failures + --- + duration_ms: 0.468377 + type: 'test' + ... +# Subtest: CommentThreadService persists caches safely during teardown failures +ok 4 - CommentThreadService persists caches safely during teardown failures + --- + duration_ms: 1.809545 + type: 'test' + ... +# Subtest: CommentThreadService logs cache usage and fallback decisions +ok 5 - CommentThreadService logs cache usage and fallback decisions + --- + duration_ms: 1.334692 + type: 'test' + ... +# Subtest: CommentThreadService normalizes mixed-case event ids in thread state +ok 6 - CommentThreadService normalizes mixed-case event ids in thread state + --- + duration_ms: 2.089179 + type: 'test' + ... +# Subtest: CommentThreadService normalizes mixed-case pubkeys during hydration +ok 7 - CommentThreadService normalizes mixed-case pubkeys during hydration + --- + duration_ms: 1.216243 + type: 'test' + ... +# Subtest: CommentThreadService deduplicates mixed-case event ids and pubkeys +ok 8 - CommentThreadService deduplicates mixed-case event ids and pubkeys + --- + duration_ms: 1.115588 + type: 'test' + ... +# Subtest: CommentThreadService retries profile hydration before succeeding +ok 9 - CommentThreadService retries profile hydration before succeeding + --- + duration_ms: 77.03844 + type: 'test' + ... +# Subtest: CommentThreadService surfaces profile hydration failures after retries +ok 10 - CommentThreadService surfaces profile hydration failures after retries + --- + duration_ms: 201.810724 + type: 'test' + ... +# Subtest: listVideoComments accepts builder events without parent ids and filters replies +ok 11 - listVideoComments accepts builder events without parent ids and filters replies + --- + duration_ms: 7.539646 + type: 'test' + ... +# Subtest: CommentThreadService hydrates, subscribes, and dedupes incoming comment events +ok 12 - CommentThreadService hydrates, subscribes, and dedupes incoming comment events + --- + duration_ms: 35.550535 + type: 'test' + ... +# Subtest: CommentThreadService loadThread falls back to event id when address is missing +ok 13 - CommentThreadService loadThread falls back to event id when address is missing + --- + duration_ms: 1.643731 + type: 'test' + ... +# Subtest: CommentThreadService requests and snapshots comments by root identifier +ok 14 - CommentThreadService requests and snapshots comments by root identifier + --- + duration_ms: 1.760149 + type: 'test' + ... +# Subtest: CommentThreadService falls back to pointerIdentifiers root id +ok 15 - CommentThreadService falls back to pointerIdentifiers root id + --- + duration_ms: 1.309128 + type: 'test' + ... +# Subtest: CommentThreadService preserves raw video author pubkeys during hydration fetches +ok 16 - CommentThreadService preserves raw video author pubkeys during hydration fetches + --- + duration_ms: 9.585084 + type: 'test' + ... +# Subtest: CommentThreadService teardown cancels hydration timers +ok 17 - CommentThreadService teardown cancels hydration timers + --- + duration_ms: 81.866247 + type: 'test' + ... +1..17 +# tests 17 +# suites 0 +# pass 17 +# fail 0 +# cancelled 0 +# skipped 0 +# todo 0 +# duration_ms 441.271587 + +→ Running tests/compliance/nip04_44_compliance.test.mjs +TAP version 13 +# Subtest: NIP-04/44 Compliance: Encryption Preference + # Subtest: createNip46Cipher prefers nip44.v2 when available + ok 1 - createNip46Cipher prefers nip44.v2 when available + --- + duration_ms: 23.22394 + type: 'test' + ... + # Subtest: createNip46Cipher falls back to nip04 if nip44 is missing + ok 2 - createNip46Cipher falls back to nip04 if nip44 is missing + --- + duration_ms: 9.620548 + type: 'test' + ... + 1..2 +ok 1 - NIP-04/44 Compliance: Encryption Preference + --- + duration_ms: 116.21281 + type: 'test' + ... +# Subtest: NIP-04/44 Compliance: Decryption Fallback + # Subtest: decryptNip46PayloadWithKeys handles nip44 (v2) payload + ok 1 - decryptNip46PayloadWithKeys handles nip44 (v2) payload + --- + duration_ms: 33.892268 + type: 'test' + ... + # Subtest: decryptNip46PayloadWithKeys handles nip04 payload + ok 2 - decryptNip46PayloadWithKeys handles nip04 payload + --- + duration_ms: 36.068598 + type: 'test' + ... + 1..2 +ok 2 - NIP-04/44 Compliance: Decryption Fallback + --- + duration_ms: 72.431217 + type: 'test' + ... +1..2 +# tests 6 +# suites 0 +# pass 6 +# fail 0 +# cancelled 0 +# skipped 0 +# todo 0 +# duration_ms 204.996037 + +→ Running tests/compliance/nip07_compliance.test.mjs +TAP version 13 +# Subtest: NIP-07 Compliance: Retry Logic + # Subtest: runNip07WithRetry succeeds on first try + ok 1 - runNip07WithRetry succeeds on first try + --- + duration_ms: 2.439712 + type: 'test' + ... + # Subtest: runNip07WithRetry retries on timeout error + ok 2 - runNip07WithRetry retries on timeout error + --- + duration_ms: 20.479054 + type: 'test' + ... + # Subtest: runNip07WithRetry fails after max retries or if error is not timeout + ok 3 - runNip07WithRetry fails after max retries or if error is not timeout + --- + duration_ms: 1.482074 + type: 'test' + ... + 1..3 +ok 1 - NIP-07 Compliance: Retry Logic + --- + duration_ms: 26.540698 + type: 'test' + ... +1..1 +# tests 4 +# suites 0 +# pass 4 +# fail 0 +# cancelled 0 +# skipped 0 +# todo 0 +# duration_ms 60.483448 + +→ Running tests/compliance/nip65_compliance.test.mjs +TAP version 13 +# Subtest: NIP-65 Compliance: Relay List Loading + # Subtest: loadRelayList requests Kind 10002 + ok 1 - loadRelayList requests Kind 10002 + --- + duration_ms: 8.413927 + type: 'test' + ... + # Subtest: loadRelayList parses r tags correctly + ok 2 - loadRelayList parses r tags correctly + --- + duration_ms: 0.985872 + type: 'test' + ... + 1..2 +ok 1 - NIP-65 Compliance: Relay List Loading + --- + duration_ms: 182.069901 + type: 'test' + ... +1..1 +# tests 3 +# suites 0 +# pass 3 +# fail 0 +# cancelled 0 +# skipped 0 +# todo 0 +# duration_ms 197.98346 + +→ Running tests/compliance/video_note_compliance.test.mjs +TAP version 13 +# Subtest: Video Note Compliance (Kind 30078 & NIP-71) + # Subtest: prepareVideoPublishPayload creates Kind 30078 event + ok 1 - prepareVideoPublishPayload creates Kind 30078 event + --- + duration_ms: 2.807829 + type: 'test' + ... + # Subtest: prepareVideoPublishPayload includes NIP-71 tags when provided + ok 2 - prepareVideoPublishPayload includes NIP-71 tags when provided + --- + duration_ms: 1.083481 + type: 'test' + ... + 1..2 +ok 1 - Video Note Compliance (Kind 30078 & NIP-71) + --- + duration_ms: 46.331627 + type: 'test' + ... +1..1 +# tests 3 +# suites 0 +# pass 3 +# fail 0 +# cancelled 0 +# skipped 0 +# todo 0 +# duration_ms 59.602005 + +→ Running tests/design-system-metrics.test.mjs +TAP version 13 +# Subtest: metric probe falls back to numeric parsing when measurement fails +ok 1 - metric probe falls back to numeric parsing when measurement fails + --- + duration_ms: 392.666207 + type: 'test' + ... +1..1 +# tests 1 +# suites 0 +# pass 1 +# fail 0 +# cancelled 0 +# skipped 0 +# todo 0 +# duration_ms 407.84542 + +→ Running tests/designSystem/dynamicStyles.test.mjs +TAP version 13 +# Subtest: js/designSystem/dynamicStyles.js + # Subtest: registerScope + # Subtest: should register a scope and return a string ID + ok 1 - should register a scope and return a string ID + --- + duration_ms: 109.44923 + type: 'test' + ... + # Subtest: should create a style element or use adoptedStyleSheets + ok 2 - should create a style element or use adoptedStyleSheets + --- + duration_ms: 17.355053 + type: 'test' + ... + # Subtest: should insert rules with the correct selector + ok 3 - should insert rules with the correct selector + --- + duration_ms: 14.264298 + type: 'test' + ... + # Subtest: should handle "&" in selectors + ok 4 - should handle "&" in selectors + --- + duration_ms: 11.458493 + type: 'test' + ... + 1..4 + ok 1 - registerScope + --- + duration_ms: 153.848522 + type: 'suite' + ... + # Subtest: setVariables + # Subtest: should update CSS variables on the scope + ok 1 - should update CSS variables on the scope + --- + duration_ms: 12.98051 + type: 'test' + ... + # Subtest: should handle removing variables + ok 2 - should handle removing variables + --- + duration_ms: 17.593718 + type: 'test' + ... + 1..2 + ok 2 - setVariables + --- + duration_ms: 30.937447 + type: 'suite' + ... + # Subtest: releaseScope + # Subtest: should remove rules and clean up + ok 1 - should remove rules and clean up + --- + duration_ms: 11.017123 + type: 'test' + ... + # Subtest: should return false for non-existent scope + ok 2 - should return false for non-existent scope + --- + duration_ms: 8.685664 + type: 'test' + ... + 1..2 + ok 3 - releaseScope + --- + duration_ms: 20.161695 + type: 'suite' + ... + # Subtest: Isolation + # Subtest: should manage scopes independently for different documents + ok 1 - should manage scopes independently for different documents + --- + duration_ms: 30.921658 + type: 'test' + ... + 1..1 + ok 4 - Isolation + --- + duration_ms: 31.085196 + type: 'suite' + ... + # Subtest: Edge cases + # Subtest: should handle invalid selectors gracefully + ok 1 - should handle invalid selectors gracefully + --- + duration_ms: 11.560591 + type: 'test' + ... + # Subtest: should handle missing document gracefully + ok 2 - should handle missing document gracefully + --- + duration_ms: 7.146808 + type: 'test' + ... + # Subtest: should fallback to