feat(binary-codec): Binary V3 codec + Invoice schema refactoring#2
Merged
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
…ssion - Add binary codec library with base62 encoding for URL-safe output - Implement encoder/decoder v1, v2, v3 with progressive optimizations - Add dictionary-based compression for common invoice fields - Add pako for gzip compression (better ratio than lz-string) - Include /compare page for testing compression strategies - Add invoice generator test utilities 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Visual documentation covering: - Architecture overview with ASCII diagrams - Compression pipeline (V1 → V2 → V3) - Binary format specification with byte layouts - Data type transformations (UUID, Address, VarInt) - Dictionary system for currencies/tokens - Benchmarks showing 2-3x capacity improvement 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
8e4c125 to
316197c
Compare
P0.15.6 Invoice Schema Field Renaming BREAKING CHANGE: All InvoiceSchemaV1 field names changed from abbreviated to human-readable format. Old URLs will not decode. Field renames: - v → version - id → invoiceId - iss → issuedAt - due → dueAt - nt → notes - net → networkId - cur → currency - t → tokenAddress - dec → decimals - f → from - c → client - it → items - dsc → discount Nested party fields (from/client): - n → name - a → walletAddress - e → email - ads → physicalAddress - ph → phone - NEW: taxId (optional) Nested item fields: - d → description - q → quantity - r → rate 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Update encode.ts to use Binary V3 encoder with hash fragments (#) - Update decode.ts to use Binary V3 decoder - Fix encoder/decoder to treat invoiceId as user string (not UUID) - Add OG preview encoder/decoder for social sharing - Add useHashFragment hook for SSR-safe hash reading - Update URL format: /pay?d=... → /pay#H... (privacy-first) - Add @deprecated to LZ-String compression functions - Update tests for Binary V3 format and address normalization BREAKING CHANGE: URL format changed from query params to hash fragments. Existing URLs using ?d= will no longer work. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Rename schema.ts → schema-v2.ts - Update interface name: InvoiceSchemaV1 → InvoiceSchemaV2 - Bump wire format version from 1 to 2 - Update all decoders (v1, v2, v3) to return version: 2 - Update validation schema to expect version: 2 - Update all tests, demo data, and invoice generator - Breaking change: existing URLs with version: 1 will fail validation 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…rStore - Remove InvoiceDraft, use DraftState (meta + Partial<Invoice>) - Add separate LineItem[] for React key management - Migrate v0 (old InvoiceDraft) to v1 store with version: 2 Invoice - Rename: recipient→client, sender→from, chainId→networkId - Convert dates: ISO strings to Unix timestamps - Update auto-save, generate-invoice, TemplateList chore(binary-codec): remove V1/V2, keep only V3 - Delete encoder.ts, encoder-v2.ts, decoder.ts, decoder-v2.ts - Update index.ts to export only V3 functions - Remove /compare benchmark page (no longer needed) Breaking: CreatorStore schema changed (auto-migrated) Breaking: Binary codec V1/V2 removed (MVP, no production users) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Specs belong in voidpay-ai repository, not voidpay code repo. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Extract network short codes from og-preview.ts to entities/network following FSD principles - business constants belong in entities layer. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replaced by Binary V3 codec with 40-50% better compression. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Replace separate fields (invoiceId, recipientName, totalAmount) with `invoice: Invoice` - Add formatInvoiceTotal() helper for display - Update all consumers: search, sort, import, UI - Delete unused migrations.ts - Rewrite invoice-codec README for Binary V3 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add taxId field rendering to PartyInfo for both from/client sections - Migrate lucide-react icons to inline SVGs (Mail, Phone, MapPin, Wallet, Hash) - Export new icons from shared/ui for bundle optimization - Add first:mt-0 to fix margin when wallet/address is first element - Update demo invoices with diverse optional field combinations - Add taxId to test mock data and new test case 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
ignromanov
added a commit
that referenced
this pull request
Mar 31, 2026
- Fix txHash #1 missing 2 hex chars (62→64 hex digits) - Remove redundant "(40 hours)" from description where qty=40 - Change Invoice #2 discount from 8% to 5% so tax/discount don't cancel out - Fix native token (ETH, POL) not recognized when loading invoice as template: spread merge didn't clear default tokenAddress when decoded data omits the key
ignromanov
added a commit
that referenced
this pull request
Apr 14, 2026
…ity (#137) * docs: update privacy policy with Umami analytics details Add dedicated "Product Analytics" section, add Umami to Third-Party Services, fix misleading "Analytics or telemetry" item in "What We Don't Collect" section. * fix(demo): correct demo invoice data and native token template loading - Fix txHash #1 missing 2 hex chars (62→64 hex digits) - Remove redundant "(40 hours)" from description where qty=40 - Change Invoice #2 discount from 8% to 5% so tax/discount don't cancel out - Fix native token (ETH, POL) not recognized when loading invoice as template: spread merge didn't clear default tokenAddress when decoded data omits the key * docs: add community files, security policy, README redesign - LICENSE (MIT) - SECURITY.md + public/.well-known/security.txt (RFC 9116) - CONTRIBUTING.md, CODE_OF_CONDUCT.md (Contributor Covenant v2.1) - README.md full redesign: badges, How It Works, features, quick start - .github/FUNDING.yml (GitHub Sponsors + Giveth) - .github/dependabot.yml (weekly npm, monthly GHA) - .github/pull_request_template.md - .github/ISSUE_TEMPLATE/feature_request.md * fix(docs): simplify PR template to match existing style Summary + Test plan (lowercase), no generic checklist — CI handles validation. * fix(docs): PR template with structured summary and specific test plan Matches PR #45 style: subsections for larger PRs, concrete test checkboxes. * ci: add Dependabot auto-merge for patch and minor updates Auto-approve and squash-merge Dependabot PRs for patch/minor versions after CI passes. Major version updates require manual review. * build(deps-dev): bump tailwindcss from 4.1.18 to 4.2.2 (#70) Bumps [tailwindcss](https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/tailwindcss) from 4.1.18 to 4.2.2. - [Release notes](https://github.com/tailwindlabs/tailwindcss/releases) - [Changelog](https://github.com/tailwindlabs/tailwindcss/blob/main/CHANGELOG.md) - [Commits](https://github.com/tailwindlabs/tailwindcss/commits/v4.2.2/packages/tailwindcss) --- updated-dependencies: - dependency-name: tailwindcss dependency-version: 4.2.2 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump tailwind-merge from 3.4.0 to 3.5.0 (#62) Bumps [tailwind-merge](https://github.com/dcastil/tailwind-merge) from 3.4.0 to 3.5.0. - [Release notes](https://github.com/dcastil/tailwind-merge/releases) - [Commits](https://github.com/dcastil/tailwind-merge/compare/v3.4.0...v3.5.0) --- updated-dependencies: - dependency-name: tailwind-merge dependency-version: 3.5.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump zustand from 5.0.9 to 5.0.12 (#68) Bumps [zustand](https://github.com/pmndrs/zustand) from 5.0.9 to 5.0.12. - [Release notes](https://github.com/pmndrs/zustand/releases) - [Commits](https://github.com/pmndrs/zustand/compare/v5.0.9...v5.0.12) --- updated-dependencies: - dependency-name: zustand dependency-version: 5.0.12 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps-dev): bump lint-staged from 16.2.7 to 16.4.0 (#61) Bumps [lint-staged](https://github.com/lint-staged/lint-staged) from 16.2.7 to 16.4.0. - [Release notes](https://github.com/lint-staged/lint-staged/releases) - [Changelog](https://github.com/lint-staged/lint-staged/blob/main/CHANGELOG.md) - [Commits](https://github.com/lint-staged/lint-staged/compare/v16.2.7...v16.4.0) --- updated-dependencies: - dependency-name: lint-staged dependency-version: 16.4.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump viem from 2.43.4 to 2.47.6 (#63) Bumps [viem](https://github.com/wevm/viem) from 2.43.4 to 2.47.6. - [Release notes](https://github.com/wevm/viem/releases) - [Commits](https://github.com/wevm/viem/compare/viem@2.43.4...viem@2.47.6) --- updated-dependencies: - dependency-name: viem dependency-version: 2.47.6 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps-dev): bump @next/eslint-plugin-next from 16.1.1 to 16.2.1 (#69) Bumps [@next/eslint-plugin-next](https://github.com/vercel/next.js/tree/HEAD/packages/eslint-plugin-next) from 16.1.1 to 16.2.1. - [Release notes](https://github.com/vercel/next.js/releases) - [Changelog](https://github.com/vercel/next.js/blob/canary/release.js) - [Commits](https://github.com/vercel/next.js/commits/v16.2.1/packages/eslint-plugin-next) --- updated-dependencies: - dependency-name: "@next/eslint-plugin-next" dependency-version: 16.2.1 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump zod from 4.3.4 to 4.3.6 (#66) Bumps [zod](https://github.com/colinhacks/zod) from 4.3.4 to 4.3.6. - [Release notes](https://github.com/colinhacks/zod/releases) - [Commits](https://github.com/colinhacks/zod/compare/v4.3.4...v4.3.6) --- updated-dependencies: - dependency-name: zod dependency-version: 4.3.6 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * fix(github): issue templates frontmatter, dependabot auto-merge workflow - Add name/about/title/assignees to issue templates so GitHub recognizes them - Create config.yml disabling blank issues with security advisory link - Replace dependabot-auto-merge.yml with simplified dependabot-automerge.yml * build(deps-dev): bump lucide-static from 0.577.0 to 1.7.0 (#67) Bumps [lucide-static](https://github.com/lucide-icons/lucide) from 0.577.0 to 1.7.0. - [Release notes](https://github.com/lucide-icons/lucide/releases) - [Commits](https://github.com/lucide-icons/lucide/compare/0.577.0...1.7.0) --- updated-dependencies: - dependency-name: lucide-static dependency-version: 1.7.0 dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps-dev): bump @types/node from 22.19.3 to 25.5.0 (#65) Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 22.19.3 to 25.5.0. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node) --- updated-dependencies: - dependency-name: "@types/node" dependency-version: 25.5.0 dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump actions/upload-artifact from 4 to 7 (#60) Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4 to 7. - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/v4...v7) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-version: '7' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump pnpm/action-setup from 4 to 5 (#59) Bumps [pnpm/action-setup](https://github.com/pnpm/action-setup) from 4 to 5. - [Release notes](https://github.com/pnpm/action-setup/releases) - [Commits](https://github.com/pnpm/action-setup/compare/v4...v5) --- updated-dependencies: - dependency-name: pnpm/action-setup dependency-version: '5' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump actions/checkout from 4 to 6 (#58) Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 6. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v4...v6) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump actions/cache from 4 to 5 (#57) Bumps [actions/cache](https://github.com/actions/cache) from 4 to 5. - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](https://github.com/actions/cache/compare/v4...v5) --- updated-dependencies: - dependency-name: actions/cache dependency-version: '5' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump actions/setup-node from 4 to 6 (#56) Bumps [actions/setup-node](https://github.com/actions/setup-node) from 4 to 6. - [Release notes](https://github.com/actions/setup-node/releases) - [Commits](https://github.com/actions/setup-node/compare/v4...v6) --- updated-dependencies: - dependency-name: actions/setup-node dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump picomatch from 2.3.1 to 2.3.2 (#55) Bumps [picomatch](https://github.com/micromatch/picomatch) from 2.3.1 to 2.3.2. - [Release notes](https://github.com/micromatch/picomatch/releases) - [Changelog](https://github.com/micromatch/picomatch/blob/master/CHANGELOG.md) - [Commits](https://github.com/micromatch/picomatch/compare/2.3.1...2.3.2) --- updated-dependencies: - dependency-name: picomatch dependency-version: 2.3.2 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps-dev): bump vitest and @vitest/coverage-istanbul (#64) Bumps [vitest](https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest) and [@vitest/coverage-istanbul](https://github.com/vitest-dev/vitest/tree/HEAD/packages/coverage-istanbul). These dependencies needed to be updated together. Updates `vitest` from 4.0.16 to 4.1.2 - [Release notes](https://github.com/vitest-dev/vitest/releases) - [Commits](https://github.com/vitest-dev/vitest/commits/v4.1.2/packages/vitest) Updates `@vitest/coverage-istanbul` from 4.0.16 to 4.1.2 - [Release notes](https://github.com/vitest-dev/vitest/releases) - [Commits](https://github.com/vitest-dev/vitest/commits/v4.1.2/packages/coverage-istanbul) --- updated-dependencies: - dependency-name: vitest dependency-version: 4.1.2 dependency-type: direct:development update-type: version-update:semver-minor - dependency-name: "@vitest/coverage-istanbul" dependency-version: 4.1.2 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump the npm_and_yarn group across 1 directory with 11 updates (#71) Bumps the npm_and_yarn group with 11 updates in the / directory: | Package | From | To | | --- | --- | --- | | [next](https://github.com/vercel/next.js) | `15.5.9` | `15.5.14` | | [happy-dom](https://github.com/capricorn86/happy-dom) | `20.0.11` | `20.8.9` | | [ajv](https://github.com/ajv-validator/ajv) | `6.12.6` | `6.14.0` | | [axios](https://github.com/axios/axios) | `1.13.2` | `1.14.0` | | [brace-expansion](https://github.com/juliangruber/brace-expansion) | `1.1.12` | `1.1.13` | | [flatted](https://github.com/WebReflection/flatted) | `3.3.3` | `3.4.2` | | [h3](https://github.com/h3js/h3) | `1.15.4` | `1.15.10` | | [hono](https://github.com/honojs/hono) | `4.11.3` | `4.12.9` | | [minimatch](https://github.com/isaacs/minimatch) | `3.1.2` | `3.1.5` | | [rollup](https://github.com/rollup/rollup) | `4.54.0` | `4.60.1` | | [socket.io-parser](https://github.com/socketio/socket.io) | `4.2.5` | `4.2.6` | Updates `next` from 15.5.9 to 15.5.14 - [Release notes](https://github.com/vercel/next.js/releases) - [Changelog](https://github.com/vercel/next.js/blob/canary/release.js) - [Commits](https://github.com/vercel/next.js/compare/v15.5.9...v15.5.14) Updates `happy-dom` from 20.0.11 to 20.8.9 - [Release notes](https://github.com/capricorn86/happy-dom/releases) - [Commits](https://github.com/capricorn86/happy-dom/compare/v20.0.11...v20.8.9) Updates `ajv` from 6.12.6 to 6.14.0 - [Release notes](https://github.com/ajv-validator/ajv/releases) - [Commits](https://github.com/ajv-validator/ajv/compare/v6.12.6...v6.14.0) Updates `axios` from 1.13.2 to 1.14.0 - [Release notes](https://github.com/axios/axios/releases) - [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md) - [Commits](https://github.com/axios/axios/compare/v1.13.2...v1.14.0) Updates `brace-expansion` from 1.1.12 to 1.1.13 - [Release notes](https://github.com/juliangruber/brace-expansion/releases) - [Commits](https://github.com/juliangruber/brace-expansion/compare/v1.1.12...v1.1.13) Updates `flatted` from 3.3.3 to 3.4.2 - [Commits](https://github.com/WebReflection/flatted/compare/v3.3.3...v3.4.2) Updates `h3` from 1.15.4 to 1.15.10 - [Release notes](https://github.com/h3js/h3/releases) - [Changelog](https://github.com/h3js/h3/blob/v1.15.10/CHANGELOG.md) - [Commits](https://github.com/h3js/h3/compare/v1.15.4...v1.15.10) Updates `hono` from 4.11.3 to 4.12.9 - [Release notes](https://github.com/honojs/hono/releases) - [Commits](https://github.com/honojs/hono/compare/v4.11.3...v4.12.9) Updates `minimatch` from 3.1.2 to 3.1.5 - [Changelog](https://github.com/isaacs/minimatch/blob/main/changelog.md) - [Commits](https://github.com/isaacs/minimatch/compare/v3.1.2...v3.1.5) Updates `rollup` from 4.54.0 to 4.60.1 - [Release notes](https://github.com/rollup/rollup/releases) - [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md) - [Commits](https://github.com/rollup/rollup/compare/v4.54.0...v4.60.1) Updates `socket.io-parser` from 4.2.5 to 4.2.6 - [Release notes](https://github.com/socketio/socket.io/releases) - [Changelog](https://github.com/socketio/socket.io/blob/main/CHANGELOG.md) - [Commits](https://github.com/socketio/socket.io/compare/socket.io-parser@4.2.5...socket.io-parser@4.2.6) --- updated-dependencies: - dependency-name: next dependency-version: 15.5.14 dependency-type: direct:production dependency-group: npm_and_yarn - dependency-name: happy-dom dependency-version: 20.8.9 dependency-type: direct:development dependency-group: npm_and_yarn - dependency-name: ajv dependency-version: 6.14.0 dependency-type: indirect dependency-group: npm_and_yarn - dependency-name: axios dependency-version: 1.14.0 dependency-type: indirect dependency-group: npm_and_yarn - dependency-name: brace-expansion dependency-version: 1.1.13 dependency-type: indirect dependency-group: npm_and_yarn - dependency-name: flatted dependency-version: 3.4.2 dependency-type: indirect dependency-group: npm_and_yarn - dependency-name: h3 dependency-version: 1.15.10 dependency-type: indirect dependency-group: npm_and_yarn - dependency-name: hono dependency-version: 4.12.9 dependency-type: indirect dependency-group: npm_and_yarn - dependency-name: minimatch dependency-version: 3.1.5 dependency-type: indirect dependency-group: npm_and_yarn - dependency-name: rollup dependency-version: 4.60.1 dependency-type: indirect dependency-group: npm_and_yarn - dependency-name: socket.io-parser dependency-version: 4.2.6 dependency-type: indirect dependency-group: npm_and_yarn ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump yaml from 2.8.2 to 2.8.3 (#53) Bumps [yaml](https://github.com/eemeli/yaml) from 2.8.2 to 2.8.3. - [Release notes](https://github.com/eemeli/yaml/releases) - [Commits](https://github.com/eemeli/yaml/compare/v2.8.2...v2.8.3) --- updated-dependencies: - dependency-name: yaml dependency-version: 2.8.3 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump @xmldom/xmldom (#72) Bumps the npm_and_yarn group with 1 update in the / directory: [@xmldom/xmldom](https://github.com/xmldom/xmldom). Updates `@xmldom/xmldom` from 0.8.11 to 0.8.12 - [Release notes](https://github.com/xmldom/xmldom/releases) - [Changelog](https://github.com/xmldom/xmldom/blob/master/CHANGELOG.md) - [Commits](https://github.com/xmldom/xmldom/compare/0.8.11...0.8.12) --- updated-dependencies: - dependency-name: "@xmldom/xmldom" dependency-version: 0.8.12 dependency-type: indirect dependency-group: npm_and_yarn ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * docs: add Drips FUNDING.json + fix Giveth URL in FUNDING.yml - FUNDING.json: Drips Network project claim (treasury wallet) - FUNDING.yml: correct Giveth project URL slug * Add newline at end of FUNDING.json Fix formatting by adding a newline at the end of the file. * docs: add OP Atlas projectId to FUNDING.json * docs: add Optimism network to Drips FUNDING.json * docs: add Buy Me a Coffee to FUNDING.yml * build(deps): bump lodash in the npm_and_yarn group across 1 directory (#78) Bumps the npm_and_yarn group with 1 update in the / directory: [lodash](https://github.com/lodash/lodash). Updates `lodash` from 4.17.21 to 4.18.1 - [Release notes](https://github.com/lodash/lodash/releases) - [Commits](https://github.com/lodash/lodash/compare/4.17.21...4.18.1) --- updated-dependencies: - dependency-name: lodash dependency-version: 4.18.1 dependency-type: indirect dependency-group: npm_and_yarn ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump defu in the npm_and_yarn group across 1 directory (#80) Bumps the npm_and_yarn group with 1 update in the / directory: [defu](https://github.com/unjs/defu). Updates `defu` from 6.1.4 to 6.1.6 - [Release notes](https://github.com/unjs/defu/releases) - [Changelog](https://github.com/unjs/defu/blob/main/CHANGELOG.md) - [Commits](https://github.com/unjs/defu/compare/v6.1.4...v6.1.6) --- updated-dependencies: - dependency-name: defu dependency-version: 6.1.6 dependency-type: indirect dependency-group: npm_and_yarn ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * fix: remove robots.txt (static export doesn't serve it) * feat: add 512x512 app icon for PWA and social sharing * feat: add TalentApp domain verification meta tag * build(deps): bump @tanstack/react-query from 5.90.16 to 5.96.2 (#82) Bumps [@tanstack/react-query](https://github.com/TanStack/query/tree/HEAD/packages/react-query) from 5.90.16 to 5.96.2. - [Release notes](https://github.com/TanStack/query/releases) - [Changelog](https://github.com/TanStack/query/blob/main/packages/react-query/CHANGELOG.md) - [Commits](https://github.com/TanStack/query/commits/@tanstack/react-query@5.96.2/packages/react-query) --- updated-dependencies: - dependency-name: "@tanstack/react-query" dependency-version: 5.96.2 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps-dev): bump @next/eslint-plugin-next from 16.2.1 to 16.2.2 (#84) Bumps [@next/eslint-plugin-next](https://github.com/vercel/next.js/tree/HEAD/packages/eslint-plugin-next) from 16.2.1 to 16.2.2. - [Release notes](https://github.com/vercel/next.js/releases) - [Changelog](https://github.com/vercel/next.js/blob/canary/release.js) - [Commits](https://github.com/vercel/next.js/commits/v16.2.2/packages/eslint-plugin-next) --- updated-dependencies: - dependency-name: "@next/eslint-plugin-next" dependency-version: 16.2.2 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump framer-motion from 12.23.26 to 12.38.0 (#87) Bumps [framer-motion](https://github.com/motiondivision/motion) from 12.23.26 to 12.38.0. - [Changelog](https://github.com/motiondivision/motion/blob/main/CHANGELOG.md) - [Commits](https://github.com/motiondivision/motion/compare/v12.23.26...v12.38.0) --- updated-dependencies: - dependency-name: framer-motion dependency-version: 12.38.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps-dev): bump @vitejs/plugin-react from 5.1.2 to 5.2.0 (#88) Bumps [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/tree/HEAD/packages/plugin-react) from 5.1.2 to 5.2.0. - [Release notes](https://github.com/vitejs/vite-plugin-react/releases) - [Changelog](https://github.com/vitejs/vite-plugin-react/blob/plugin-react@5.2.0/packages/plugin-react/CHANGELOG.md) - [Commits](https://github.com/vitejs/vite-plugin-react/commits/plugin-react@5.2.0/packages/plugin-react) --- updated-dependencies: - dependency-name: "@vitejs/plugin-react" dependency-version: 5.2.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps-dev): bump postcss from 8.5.6 to 8.5.8 (#89) Bumps [postcss](https://github.com/postcss/postcss) from 8.5.6 to 8.5.8. - [Release notes](https://github.com/postcss/postcss/releases) - [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md) - [Commits](https://github.com/postcss/postcss/compare/8.5.6...8.5.8) --- updated-dependencies: - dependency-name: postcss dependency-version: 8.5.8 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps-dev): bump typescript-eslint from 8.51.0 to 8.58.0 (#92) Bumps [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint) from 8.51.0 to 8.58.0. - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-eslint/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.58.0/packages/typescript-eslint) --- updated-dependencies: - dependency-name: typescript-eslint dependency-version: 8.58.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps-dev): bump @testing-library/react from 16.3.1 to 16.3.2 (#93) Bumps [@testing-library/react](https://github.com/testing-library/react-testing-library) from 16.3.1 to 16.3.2. - [Release notes](https://github.com/testing-library/react-testing-library/releases) - [Changelog](https://github.com/testing-library/react-testing-library/blob/main/CHANGELOG.md) - [Commits](https://github.com/testing-library/react-testing-library/compare/v16.3.1...v16.3.2) --- updated-dependencies: - dependency-name: "@testing-library/react" dependency-version: 16.3.2 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump @web3icons/react from 4.1.14 to 4.1.17 (#94) Bumps [@web3icons/react](https://github.com/0xa3k5/web3icons/tree/HEAD/packages/react) from 4.1.14 to 4.1.17. - [Release notes](https://github.com/0xa3k5/web3icons/releases) - [Changelog](https://github.com/0xa3k5/web3icons/blob/main/packages/react/CHANGELOG.md) - [Commits](https://github.com/0xa3k5/web3icons/commits/@web3icons/react@4.1.17/packages/react) --- updated-dependencies: - dependency-name: "@web3icons/react" dependency-version: 4.1.17 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump @upstash/ratelimit from 2.0.7 to 2.0.8 (#91) Bumps [@upstash/ratelimit](https://github.com/upstash/ratelimit) from 2.0.7 to 2.0.8. - [Release notes](https://github.com/upstash/ratelimit/releases) - [Commits](https://github.com/upstash/ratelimit/compare/v2.0.7...v2.0.8) --- updated-dependencies: - dependency-name: "@upstash/ratelimit" dependency-version: 2.0.8 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps-dev): bump @eslint/eslintrc from 3.3.3 to 3.3.5 (#96) Bumps [@eslint/eslintrc](https://github.com/eslint/eslintrc) from 3.3.3 to 3.3.5. - [Release notes](https://github.com/eslint/eslintrc/releases) - [Changelog](https://github.com/eslint/eslintrc/blob/main/CHANGELOG.md) - [Commits](https://github.com/eslint/eslintrc/compare/eslintrc-v3.3.3...eslintrc-v3.3.5) --- updated-dependencies: - dependency-name: "@eslint/eslintrc" dependency-version: 3.3.5 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump pixi.js from 8.14.3 to 8.17.1 (#100) Bumps [pixi.js](https://github.com/pixijs/pixijs) from 8.14.3 to 8.17.1. - [Release notes](https://github.com/pixijs/pixijs/releases) - [Commits](https://github.com/pixijs/pixijs/compare/v8.14.3...v8.17.1) --- updated-dependencies: - dependency-name: pixi.js dependency-version: 8.17.1 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump geist from 1.5.1 to 1.7.0 (#98) Bumps [geist](https://github.com/vercel/geist-font/tree/HEAD/packages/next) from 1.5.1 to 1.7.0. - [Release notes](https://github.com/vercel/geist-font/releases) - [Changelog](https://github.com/vercel/geist-font/blob/main/packages/next/CHANGELOG.md) - [Commits](https://github.com/vercel/geist-font/commits/geist@1.7.0/packages/next) --- updated-dependencies: - dependency-name: geist dependency-version: 1.7.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps-dev): bump @types/node from 25.5.0 to 25.5.2 (#99) Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 25.5.0 to 25.5.2. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node) --- updated-dependencies: - dependency-name: "@types/node" dependency-version: 25.5.2 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump viem from 2.47.6 to 2.47.10 (#97) Bumps [viem](https://github.com/wevm/viem) from 2.47.6 to 2.47.10. - [Release notes](https://github.com/wevm/viem/releases) - [Commits](https://github.com/wevm/viem/compare/viem@2.47.6...viem@2.47.10) --- updated-dependencies: - dependency-name: viem dependency-version: 2.47.10 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps-dev): bump @eslint/js from 9.39.2 to 9.39.4 (#101) Bumps [@eslint/js](https://github.com/eslint/eslint/tree/HEAD/packages/js) from 9.39.2 to 9.39.4. - [Release notes](https://github.com/eslint/eslint/releases) - [Commits](https://github.com/eslint/eslint/commits/v9.39.4/packages/js) --- updated-dependencies: - dependency-name: "@eslint/js" dependency-version: 9.39.4 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps-dev): bump vite in the npm_and_yarn group across 1 directory (#102) Bumps the npm_and_yarn group with 1 update in the / directory: [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite). Updates `vite` from 7.3.0 to 7.3.2 - [Release notes](https://github.com/vitejs/vite/releases) - [Changelog](https://github.com/vitejs/vite/blob/v7.3.2/packages/vite/CHANGELOG.md) - [Commits](https://github.com/vitejs/vite/commits/v7.3.2/packages/vite) --- updated-dependencies: - dependency-name: vite dependency-version: 7.3.2 dependency-type: direct:development dependency-group: npm_and_yarn ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * refactor(history): redesign history page cards with payment panel style (#103) * feat(history): add StatusGradientBar component * feat(history): add NetworkBadge component with tests * refactor(history): redesign InvoiceStatusBadge with dot + glow * refactor(history): restyle InvoiceCardShell with zinc-900 + gradient bar * refactor(history): rewrite HistoryList with new card layout, network badge, subtotal * refactor(history): rewrite ReceivedInvoiceList with unified card design + Template button * refactor(history): update HistoryWorkspace colors gray→zinc * fix(history): remove unused type imports in ReceivedInvoiceList * refactor(history): extract shared InvoiceCard, remove duplicate card components Unified HistoryEntryCard and ReceivedInvoiceCard (~95% identical) into a single InvoiceCard with a nameLabel prop. Removed defeated memo(), pointless useMemo, dead source prop, and unnecessary JSX comments. Collapsed identical DecodedReceivedInvoice type into alias for DecodedHistoryEntry. * refactor(history): consolidate duplicated configs, merge list components - Merge HistoryList + ReceivedInvoiceList into unified InvoiceList with variant prop ('created'|'received') controlling route, name, empty text - Extract INVOICE_STATUS_CHIPS to entities/invoice for shared status colors consumed by InvoiceStatusBadge (features) and StatusChip (widgets) - Move network badge dark-mode colors to entities/network (NETWORK_BADGES_DARK) - Add formatDateMedium, formatDateCompact, isoToUnix to shared/lib/date-time - Remove deprecated DecodedReceivedInvoice type alias - Net -54 lines, 59/59 tests pass, tsc + lint clean * feat: add Base network (8453) + refactor network visual system (#79) * fix: remove robots.txt (static export doesn't serve it) * feat: add BaseIcon SVG component for Base network * feat: add Base (8453) and Base Sepolia (84532) to chain config * feat: add Base network metadata and codes * feat: add Base token registry (ETH, USDC, USDT) * feat: add Base provider slugs for Alchemy and Infura * feat: add Base confirmation config (OP Stack) * feat: add Base block estimation parameters * feat: add Base UI theming, badges, glows, and explorer * feat: add Base RPC URL env vars to schema * fix: add Base to theme configs, update chain count tests and snapshots * fix: add Base to NetworkIcon component (web3icons + fallback) * fix: update Base reference block from live explorer data * refactor: remove unused BaseIcon (NetworkIcon uses @web3icons/react) * fix: boost Base glow opacity (blue is subtle on dark background) * revert: restore original Base glow values * fix: resolve testnet glow/shadow/badge lookups via withTestnets helper Visual config Records (NETWORK_SHADOWS, NETWORK_GLOWS, NETWORK_GLOW_SHADOWS, NETWORK_GLOW_BORDERS, NETWORK_BADGES) were keyed by mainnet chain IDs only, causing missing glow on testnet invoices (e.g. Base Sepolia 84532). Added withTestnets() helper that auto-derives testnet entries from TESTNET_PARENT, so new networks only need one mapping update. * docs: update supported networks count and add Base to README and snapshot tests * docs: add Base to all network references across landing, legal, and test files * refactor: create canonical network palette and testnet utilities * chore: bump Node.js version to v24 in .nvmrc * chore: gitignore AI tool facades, plugins, and supabase local config * refactor: rename getNetworkTheme→getNetworkName, extract testnet utils, lowercase addresses * refactor: derive brand-tokens from palette, remove dead env vars, fix NetworkIcon a11y - NetworkTheme now aliases NetworkThemeName from network-palette (canonical source) - isValidNetworkTheme validates against NETWORK_PALETTE instead of NETWORK_THEMES - Remove 10 dead NEXT_PUBLIC_ALCHEMY/INFURA_*_URL env vars (RPC proxy uses API keys + slug maps) - NetworkIcon resolves testnet chain IDs to mainnet for icon/color/letter lookup - Add aria-label to both branded and fallback NetworkIcon paths - Export NETWORK_PALETTE and NetworkThemeName from shared/ui public API * refactor: derive network-themes from canonical palette + withTestnets * refactor: update consumers to use getNetworkThemeName, hoist widget colors * feat: add Base demo invoice, fix tokenAddress not clearing for native tokens Add 5th demo invoice for Base network (USDC, pending status) to landing page carousel. Fix react-hook-form reset() not clearing tokenAddress when loading native token templates (ETH/POL) — undefined must be mapped to '' so RHF treats it as an explicit value rather than "keep current". * fix: address PR review findings — remove unverified USDT, harden env, stabilize snapshots - Remove Base USDT token (no official Tether deployment on Base) - Add BLOCK_EXPLORERS comment explaining withTestnets exclusion - Update Base Sepolia block anchor from live RPC (28M → 39.88M) - Replace Math.random() with crypto.randomUUID() in RPC proxy - Harden validateEnv to throw in production on missing vars - Add Radix UI snapshot serializer for stable aria-controls IDs * fix: prevent stale total when switching tokens, add replaceDraft for clean data loading Total was stored as pre-calculated atomic units tied to a specific token's decimals. Switching tokens reconverted line item rates but left total stale, causing the preview to format ETH-scale values with USDC decimals (e.g. 5,510,000,000,000 instead of 5.80). - Add replaceDraft() for atomic draft replacement (hash decode, template load) - Extract toInvoiceItems/draftWithItems helpers, DRY 4 line item methods - Clear stale total on: token switch, item mutations, template save/load - Strip total from hash decode in CreateWorkspace (editor recalculates) - Handle string quantities in invoiceItemsToLineItems (old localStorage) * fix(history): resolve testnet networks showing as "Unknown" in history badges Use getNetworkName() for O(1) lookup across all networks instead of NETWORK_CONFIG.find() which only covered mainnets. Wrap NETWORK_BADGES_DARK with withTestnets() so testnet badges inherit parent network brand colors. * fix(create): reset all draft fields on form clear, extract store→form adapter draftSyncStatus leaked through reset because createNewDraft/clearDraft/replaceDraft didn't explicitly set it to 'idle'. Tax/discount/notes leaked because react-hook-form treats undefined in reset() as "keep previous value". Extract draftDataToFormValues() adapter as single source of truth for PartialInvoice→InvoiceFormValues conversion, replacing duplicated 60-line inline mappings. All optional string fields now coerced to '' on reset. * fix(test): align NetworkBadge test with getNetworkName fallback to chain ID * feat: update comparison table data to April 2026 research RF pricing changed to \$250+/mo subscription, data storage corrected to Centralized (hybrid API + on-chain, not pure IPFS), KYC/KYB updated to required (yes). Disclaimer and comment block updated to April 2026. * feat: add comparison page content data (VP vs Request Finance) * feat: add /compare/request-finance comparison page * feat: add /compare pages priority to sitemap config * feat: add link to detailed comparison from landing table * test: add comparison page tests * fix: improve comparison page UI and remove duplicate footer Apply UI/UX audit improvements: text-pretty headings, tabular-nums table, hover states, glow CTA button, visual star rating, TL;DR label, violet accent on bottom-line boxes. Remove duplicate footer links since app-level footer already exists. * ci: add project-sync workflow for auto VP Roadmap sync New issues automatically added to VP Roadmap project board with fields (Status, Priority, Advisor, Type, Source Repo) parsed from labels. Agents no longer need manual item-add. * fix(ci): use GraphQL API for project-sync workflow gh project item-add/item-edit fail with "unknown owner type" on user-level projects. Switch to direct GraphQL mutations. * chore: add .superpowers/ to gitignore * fix: invoice generation bugs — flash, source immutability, cross-tab sync (#105) * fix: prevent invoice flash on generate, preserve source immutability, add cross-tab sync - Remove clearDraft setTimeout that caused visible flash during navigation - Make TrackedInvoice.source immutable (first-write-wins) so visiting /pay doesn't overwrite 'created' to 'received' - Add localStorage storage event listener for cross-tab store rehydration * fix(ui): add cursor-pointer to CreatorHintBanner dismiss button * fix(store): key TrackedInvoice by contentHash (SHA-256) instead of invoiceId (#112) * feat(codec): add computeContentHash — SHA-256 bytes32 digest for invoice identity * feat(codec): return contentHash from parseInvoiceHash * feat(store): key TrackedInvoice by contentHash instead of invoiceId * feat(create): compute contentHash on invoice generation * feat(view): compute and expose contentHash from useInvoiceView * feat(import): compute contentHash for imported invoices * refactor(ui): wire contentHash through component hierarchy * refactor(payment): all hooks key by contentHash instead of invoiceId Updates SmartPayButtonProps, UsePaymentFlowParams, UsePaymentVerificationParams, UseFinalizationTrackerParams, UsePaymentPollingParams, and UseManualVerifyParams to accept contentHash. All store action calls (setTxHash, setError, setValidated, setFinalized, resetPaymentState, setConfirmations) now use contentHash as the key. Internal polling helpers (loops, visibility-handler) updated consistently. * fix: use contentHash key in polling params * test: update all tests for contentHash-based store key * fix: review fixes — runtime bugs, security hardening, perf improvements - Fix PaymentPanel using invoiceId instead of contentHash for store lookup (BUG-01: PDF export lost paidAt) - Fix DevStatusToggle passing invoiceId to contentHash-keyed store methods (BUG-02) - Use Promise.allSettled in migration to survive partial failures (S-01) - Always recompute contentHash on import, never trust pre-supplied values (S-02) - Add empty fragment guard in addToHistory (H-1) - Early return in setTxHash for unknown invoice (M-2) - Add console.warn to migration catch block (F-04) - Parallelize decode + hash in parseInvoiceHash via Promise.all - Parallelize import hash computation, eliminate in-place mutation * fix: resolve history page flickering and infinite migration loop - Replace non-reactive hasHydrated() with useStoreHydrated() hook that subscribes via onFinishHydration for proper React re-render on hydration - Make persist migration synchronous to avoid zustand v5 hydrationVersion race condition that cancelled in-flight async migrations - Compute contentHash post-hydration via onFinishHydration + hasHydrated guard to handle both sync and async hydration paths - Remove cross-tab storage event listener that triggered rehydrate() loops from stale tabs still writing version 1 * fix: show full invoice data in debug panel instead of decode flag * fix: skip post-hydration hash computation on v2+ stores Add _pendingHashComputation flag set only by migrate() during v1→v2 transition. _computeMissingContentHashes() now exits immediately on v2+ stores instead of reading store state on every hydration. * fix: remove console.info logs and fix test type errors Remove informational console logs from TrackedInvoiceStore (keep warnings). Add missing contentHash to SmartPayButton test fixtures. Add scrollMargin to MockIntersectionObserver for TS 5.5+ compat. * refactor: replace async crypto.subtle with sync @noble/hashes for SHA-256 Async two-phase migration (sync migrate → async post-hydration hash) caused store data loss: zustand persisted entries with empty contentHash between phases, and any failure in the async phase dropped invoices. Switch to sync SHA-256 via @noble/hashes (already a dependency via viem) so contentHash is computed atomically inside migrate(). Removes ~55 lines of async infrastructure: _pendingHashComputation, _computeMissingContentHashes, _sha256, onFinishHydration/hasHydrated fallback. * docs: fix SECURITY.md — styled-components → inline style injection, add /api/health to out-of-scope * fix(wallet): sync connection state between scoped Web3Providers LazyWalletButton in the header could stay in static placeholder state ("Connect") while PayButton's scoped provider already had the wallet connected. Root cause: LazyWalletButton only checked localStorage on mount and had no way to detect connections from other providers. Add WalletStateSync component that dispatches a custom DOM event on wallet connect, and a listener in LazyWalletButton to activate when the event fires. * fix(wallet): prevent rehydration race in scoped Web3Providers Multiple WagmiProvider instances sharing one wagmiConfig caused connector state corruption: each mount triggered rehydrate() which overwrote live connector instances with serialized plain objects from localStorage. Between rehydrate() and reconnect() completing, writeContract/sendTransaction crashed with "getChainId is not a function" because the connector lacked methods. Use WagmiContext.Provider (context-only, no hydration) for all Web3Provider instances after the first one. A module-level flag ensures only the primary instance triggers full WagmiProvider hydration + reconnect. * fix(payment): keyframe rotate to prevent SmartPay spinner freeze on Rabby framer-motion v12 with WAAPI backend stalls single-value rotate loops on the second iteration when a wallet extension's content script forces a re-render mid-mount. The breathing label kept animating (keyframes array) while the spinner icon froze (single value 360). Switching to explicit keyframes [0, 360] gives WAAPI an unambiguous start/end on every iteration and matches the pattern already used by FluidOverlay for all other infinite loops in the button tree. * fix(history): batch-check unpaid for both created and received invoices Parametrize useBatchCheck by invoice source so the History page can verify pending payments for both own and counterparty invoices, not just created. Add a Check Unpaid button to the Received section mirroring the Created one. Make invoice number and counterparty name in InvoiceCard clickable — both trigger the View action with hover/focus styling. * build(deps): bump viem from 2.47.10 to 2.47.16 (#122) Bumps [viem](https://github.com/wevm/viem) from 2.47.10 to 2.47.16. - [Release notes](https://github.com/wevm/viem/releases) - [Commits](https://github.com/wevm/viem/compare/viem@2.47.10...viem@2.47.16) --- updated-dependencies: - dependency-name: viem dependency-version: 2.47.16 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps-dev): bump typescript-eslint from 8.58.0 to 8.58.2 (#124) Bumps [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint) from 8.58.0 to 8.58.2. - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-eslint/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.58.2/packages/typescript-eslint) --- updated-dependencies: - dependency-name: typescript-eslint dependency-version: 8.58.2 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump @noble/hashes from 2.0.1 to 2.2.0 (#125) Bumps [@noble/hashes](https://github.com/paulmillr/noble-hashes) from 2.0.1 to 2.2.0. - [Release notes](https://github.com/paulmillr/noble-hashes/releases) - [Commits](https://github.com/paulmillr/noble-hashes/compare/2.0.1...2.2.0) --- updated-dependencies: - dependency-name: "@noble/hashes" dependency-version: 2.2.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps-dev): bump prettier from 3.7.4 to 3.8.2 (#126) Bumps [prettier](https://github.com/prettier/prettier) from 3.7.4 to 3.8.2. - [Release notes](https://github.com/prettier/prettier/releases) - [Changelog](https://github.com/prettier/prettier/blob/main/CHANGELOG.md) - [Commits](https://github.com/prettier/prettier/compare/3.7.4...3.8.2) --- updated-dependencies: - dependency-name: prettier dependency-version: 3.8.2 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump use-debounce from 10.0.6 to 10.1.1 (#127) Bumps [use-debounce](https://github.com/xnimorz/use-debounce) from 10.0.6 to 10.1.1. - [Release notes](https://github.com/xnimorz/use-debounce/releases) - [Changelog](https://github.com/xnimorz/use-debounce/blob/master/CHANGELOG.md) - [Commits](https://github.com/xnimorz/use-debounce/commits) --- updated-dependencies: - dependency-name: use-debounce dependency-version: 10.1.1 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump hono in the npm_and_yarn group across 1 directory (#104) Bumps the npm_and_yarn group with 1 update in the / directory: [hono](https://github.com/honojs/hono). Updates `hono` from 4.12.9 to 4.12.12 - [Release notes](https://github.com/honojs/hono/releases) - [Commits](https://github.com/honojs/hono/compare/v4.12.9...v4.12.12) --- updated-dependencies: - dependency-name: hono dependency-version: 4.12.12 dependency-type: indirect dependency-group: npm_and_yarn ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump react-hook-form from 7.70.0 to 7.72.1 (#130) Bumps [react-hook-form](https://github.com/react-hook-form/react-hook-form) from 7.70.0 to 7.72.1. - [Release notes](https://github.com/react-hook-form/react-hook-form/releases) - [Changelog](https://github.com/react-hook-form/react-hook-form/blob/master/CHANGELOG.md) - [Commits](https://github.com/react-hook-form/react-hook-form/compare/v7.70.0...v7.72.1) --- updated-dependencies: - dependency-name: react-hook-form dependency-version: 7.72.1 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps-dev): bump @tailwindcss/postcss from 4.1.18 to 4.2.2 (#131) Bumps [@tailwindcss/postcss](https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/@tailwindcss-postcss) from 4.1.18 to 4.2.2. - [Release notes](https://github.com/tailwindlabs/tailwindcss/releases) - [Changelog](https://github.com/tailwindlabs/tailwindcss/blob/main/CHANGELOG.md) - [Commits](https://github.com/tailwindlabs/tailwindcss/commits/v4.2.2/packages/@tailwindcss-postcss) --- updated-dependencies: - dependency-name: "@tailwindcss/postcss" dependency-version: 4.2.2 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps-dev): bump lucide-static from 1.7.0 to 1.8.0 (#123) Bumps [lucide-static](https://github.com/lucide-icons/lucide) from 1.7.0 to 1.8.0. - [Release notes](https://github.com/lucide-icons/lucide/releases) - [Commits](https://github.com/lucide-icons/lucide/compare/1.7.0...1.8.0) --- updated-dependencies: - dependency-name: lucide-static dependency-version: 1.8.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump @tanstack/react-query from 5.96.2 to 5.99.0 (#128) Bumps [@tanstack/react-query](https://github.com/TanStack/query/tree/HEAD/packages/react-query) from 5.96.2 to 5.99.0. - [Release notes](https://github.com/TanStack/query/releases) - [Changelog](https://github.com/TanStack/query/blob/main/packages/react-query/CHANGELOG.md) - [Commits](https://github.com/TanStack/query/commits/@tanstack/react-query@5.99.0/packages/react-query) --- updated-dependencies: - dependency-name: "@tanstack/react-query" dependency-version: 5.99.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps-dev): bump @types/node from 25.5.2 to 25.6.0 (#132) Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 25.5.2 to 25.6.0. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node) --- updated-dependencies: - dependency-name: "@types/node" dependency-version: 25.6.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps-dev): bump @next/eslint-plugin-next from 16.2.2 to 16.2.3 (#134) Bumps [@next/eslint-plugin-next](https://github.com/vercel/next.js/tree/HEAD/packages/eslint-plugin-next) from 16.2.2 to 16.2.3. - [Release notes](https://github.com/vercel/next.js/releases) - [Changelog](https://github.com/vercel/next.js/blob/canary/release.js) - [Commits](https://github.com/vercel/next.js/commits/v16.2.3/packages/eslint-plugin-next) --- updated-dependencies: - dependency-name: "@next/eslint-plugin-next" dependency-version: 16.2.3 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * feat(payment): typed wagmi error handling + onReplaced support (#115) * feat(payment): typed wagmi error handling + onReplaced support Replace fragile string-matching error classification with typed detection via viem's BaseError.walk() across the payment and wallet-connect features. Add onReplaced callback to handle user speedup/cancel of pending transactions. Component A: shared/lib/web3-errors - New module with isUserRejected, isInsufficientFunds, isChainMismatch, isReceiptNotFound, isReceiptTimeout, isTxReverted, walkCause - Walks BaseError cause chain via viem's typed API, falls back to string matching for non-BaseError edge cases (mobile WalletConnect) - 38 unit tests covering direct, wrapped, and fallback paths Component B: classifier refactor - classify-error.ts rewritten to use typed detectors before string matching - Removed step-based NETWORK_SWITCH_FAILED fallback — was masking user rejections of network switches - Added TX_REPLACED to PaymentErrorType + ERROR_MESSAGES entry - CANCELED_COPY constant for message unification - connection-error.ts now calls isUserRejected first for typed detection Component C: payment flow integration - use-payment-flow.ts: console.error moved below USER_REJECTED early return (fixes verbose wagmi stack in console on user cancel) - useWaitForTransactionReceipt now receives onReplaced callback: - reason 'cancelled' → toast + RESET (user intent) - reason 'replaced'/'repriced' → update hash + continue - New REPLACED reducer action for hash swap during confirming state - use-payment-verification.ts: sanitize raw viem errors through formatErrorMessage before writing to store + onReplaced observability * refactor(payment): address review feedback on typed wagmi error handling - Drop unused _step parameter from classifyPaymentError (dead arg after step-based fallback removal); update call site and 20+ test cases. - Fix incorrect comment in usePaymentVerification onReplaced — both hooks consume useWaitForTransactionReceipt in parallel, not sequentially. - Add TransactionExecutionError coverage to detect.test.ts (revert vs OOG shortMessage branches). * feat(payment-panel): persistent network chip across all states Adds a branded NetworkIcon + name chip at the top of PaymentPanel so payers always see which chain the payment targets — visible in pending, paid, paid-fallback and overdue states. Reserves right-side space via pr-12 to avoid overlap with the minimize button. Also migrates AmountDisplay assertions from toBeDefined() to toBeInTheDocument() per testing rules. * refactor(payment-panel): anchor network chip to amount, own minimize button Move the network chip from the panel header into each state's heading row (Total Due / Payment Successful / Expired / paid-fallback) so it sits beside the amount it qualifies — semantically tying chain to value instead of floating in an empty header strip. Extract NetworkChip into a shared presentational component to drop duplication across states. Pull the minimize button into PaymentPanel behind an onMinimize prop, removing the duplicated absolute overlay from PayWorkspace and InvoiceWorkspace. The button now coordinates with the pr-12 right-side clearance baked into every heading row. * fix(history): network icons, button sizing, robust template flow - NetworkBadge: render NetworkIcon (web3icons) before name - InvoiceCard: match Confirm/Cancel button height to regular buttons (min-h-[44px] py-2.5) to prevent layout shift on delete toggle - InvoiceList: replace fragile duplicateFromUrl + setState + push flow with hash-based navigation /create?template=1#<hash> - CreateWorkspace: detect ?template=1 and reset issuedAt/dueAt/total/ magicDust after replaceDraft so templates start with fresh dates - Remove unused duplicate-invoice.ts and its test mock * refactor(payment-panel): group network chip with due/paid date Relocates NetworkChip into a compact metadata row next to the due date (pending) or relative paidAt (paid/expired). Drops the "TOTAL DUE" label — the amount is self-explanatory and the label created a "Total Due ... Due May 2" tautology with the date chunk. - pending: [chip] Due <date> above the amount - paid: [chip] Funds sent · <relative> under Payment Successful - expired: [chip] Was due <date> · Payment disabled under header Adds formatRelativeTime() in shared/lib/date-time for ISO → "Just now" / "5 min ago" / "2 h ago" rendering. PaymentPanel now subscribes to tracked paidAt via a store selector so the subtitle reactively updates when the payment transitions to paid. Clears the chip out of the emerald amount accent box on paid state — zinc chip no longer clashes with the emerald tint. * fix(wallet): visible loading state during wagmi reconnect SmartPayButton and WalletButton both appeared frozen while wagmi restored the persisted connection: the pay button stayed on "Pay X Y" while disabled, and the header wallet button was hidden via opacity:0 so clicks fell through. Now both surfaces render an explicit disabled "Reconnecting…" state with a visible spinner and aria-busy. Covered by 6 new tests (3 SmartPayButton reconnect cases, 3 WalletButton). * fix(wallet): cover SSR pre-hydration gap in pay + header buttons Two bugs under one symptom ("click during page-load race gets stuck at Connecting"): 1. Pre-hydration gap: wagmi with `ssr: true` reports `status: 'disconnected'` on the first client render even when a persisted connection exists in localStorage. `isReconnecting` is false in that window, so the previous fix did not catch it — SmartPayButton flashed a clickable "Connect Wallet" and WalletButton did the same in the header. 2. Stuck-at-connecting race: when a user clicked through the flash, `handlePay` entered `connecting` and opened the Rainbow modal. Meanwhile wagmi finished the background reconnect. The lifecycle effect in `usePaymentFlow` checked `connectModalOpen` before `isConnected`, so if Rainbow's modal state didn't cleanly flip through the expected order the flow stayed in `connecting` forever. Fix: - New shared hook `useWagmiHydrating` detects pre-hydration (persisted connector id in localStorage + wagmi still on initial disconnected), plus the normal `connecting` / `reconnecting` statuses. Drops the pre-hydration heuristic once wagmi leaves the initial snapshot so later manual disconnect/reconnect cycles behave normally. - SmartPayButton and WalletButton now use `useWagmiHydrating` instead of `isReconnecting`. Both render a disabled loading button with aria-busy=true across the whole hydration window. - `usePaymentFlow` connecting effect now checks `isConnected` before `connectModalOpen`, so a background reconnect always wins and the flow cannot strand in `connecting`. - Regression tests: reorder-safe race in `use-payment-flow`, pre-hydration coverage in SmartPayButton + WalletButton suites. 387 payment + wallet-connect tests green. * fix(payment): cap wait-for-receipt timeout at 60s, disable retry Ensures a stuck transaction surfaces a user-visible RPC_ERROR banner within one block window instead of hanging on the spinner. Previously, viem's 180s default timeout combined with TanStack Query's default retry (3) meant the first user-visible error could be delayed by up to 9 minutes. Also drops the TEMP DEBUG console.logs added during manual test verification — all three test paths (USER_REJECTED silence, onReplaced cancel, onReplaced speedup) have been validated on Eth Sepolia + Rabby. Part of PR #115. * fix(payment): raise wait-for-receipt timeout to viem default 180s 60s was too aggressive — near-zero-gas transactions legitimately need several blocks on L1 before inclusion. Combined with retry: 0 this still caps the hidden wait at 3 minutes (vs viem's default retry × 180s = 9 minutes that motivated the original fix). Field-verified on Base Sepolia: a stuck tx now surfaces the RPC_ERROR banner as expected — only thing that needed tuning was the ceiling. Part of PR #115. * fix(payment-panel): make error banner X button clickable and cursor visible Tailwind v4 dropped the default pointer cursor on <button>, and dismissError only cleared the store — local paymentError stayed set, so the X appeared dead. Add cursor-pointer + type=button, and wire a composite handler that clears both paymentError and the tracked-invoice store error. * refactor(payment): simplify PR #115 after parallel review Findings from three parallel review agents (reuse, quality, efficiency) aggregated and fixed: - Remove dead TX_REPLACED PaymentErrorType: defined but never emitted (onReplaced dispatches REPLACED/RESET directly, classifier never returns it) - Remove walkCause from web3-errors barrel export: internal-only, test file imports from ../detect - Memoize onReplaced + extract RECEIPT_QUERY_OPTIONS/TIMEOUT_MS to module level in use-payment-flow.ts (inline refs were re-subscribing TanStack Query / viem watcher every render during confirming step) - Hoist stateless handleVerificationReplaced + memoize receiptQuery in use-payment-verification.ts (compounded by useBlockNumber watch: true) - Unwrap naked <div> wrapper with no props/layout in WalletButton.tsx - Fix misleading CANCELED_COPY comment (claimed cross-feature usage that never existed) Follow-ups tracked in #120 (NetworkChip/NetworkBadge unification), #121 (nowUnix migration). Net: -71 / +66 lines. Type-check, lint, 277 affected tests pass. * fix(payment): address PR #115 review findings - use receipt.transactionHash on CONFIRMED so replaced/repriced tx hashes aren't overwritten by the stale wagmi send hash - REPLACED reducer explicitly clears error for future-proofing - console.error logs shortMessage only to avoid leaking calldata if observability is wired later - use-payment-verification: consolidate imports above function decl - add reducer test covering REPLACED error preservation * fix(payment): correct block-time drift breaking creator-side verification Root cause: AVG_BLOCK_TIME_MS[11155111] was 12_000 but Sepolia actually runs ~13s/block. Over 35 days of forward drift estimateFromBlockHex returned a block above the real chain head; alchemy_getAssetTransfers returned empty and creators saw "payment not found" on confirmed transactions. Arbitrum Sepolia had the same class of bug (250ms assumed vs ~286ms measured). - AVG_BLOCK_TIME_MS: Sepolia 12000→13000, Arb Sepolia 250→286 (measured via 10k-block samples across all 10 supported chains). REFERENCE_BLOCKS left frozen — v1.0 shipped Mar 28, old invoices must decode with the same calibration they were created with. - /api/transfers: defense-in-depth safety net. Fetches eth_blockNumber in parallel with the transfers query, and on drifted client fromBlock retries with a 3-day lookback anchored to the real chain head. Drift logged via console.warn for observability. Eliminates the bug class regardless of anchor staleness. - scripts/measure-block-times.ts + pnpm check:block-drift: diagnostic that measures real avgBlockTime for every chain, compares vs hardcoded values, reports lookback margin, and exits non-zero on BROKEN verdict. - Route tests updated for the new parallel fetch; added cases covering both retry and no-retry paths of t…
ignromanov
added a commit
that referenced
this pull request
May 18, 2026
…k variants (AI#58) (#237) * feat(video): MicroLabel pill design — readable on any background * feat(invoice-form): InvoiceFormView renders network + token icons when ids provided * chore(video): final render p5 + S4 fix link spacing * fix(video): S0 doubled beats + remove S1 echo overlay - ThesisHookScene: beat1 visible 12→48 (was 12→30), beat2 fade-in 42→60 then holds to scene end; each beat now fully readable - scenes.ts: thesisHook 45 → 90 frames (3s) - MAGIC_DUST_PEAK_FRAME 831 → 876 (+45 for S0 extension) - CreateScene: removed echo "…is the URL." Caption (S0 holds long enough) * refactor(video): S1 inline GenerateButton + 4s scroll + correct field order - New phase frames: FROM(15) WALLET(30) CLIENT(45) LINE_DESC(60) LINE_PRICE(75) NETWORK(90) TOKEN(105) BUTTON_VISIBLE(120) - viewValue now includes walletAddress (frame>=30) and client.name "Acme Corp" (frame>=45) for more realistic form fill sequence - Line items appear progressively: description at 60, rate at 75 - focusedField sequence: from→from(wallet)→client→lineItem→network→token→undefined - Scroll keyframes [0,40,80,120] → offsets [0,-200,-400,-560] so Generate button scrolls into view at frame 120 - Dropped sticky footer div; using showGenerateButton=true so inline button lives inside InvoiceFormView scroll flow - Void glow overlay (rgba 124,58,237) pulses behind card once button appears - Removed "Link contains everything" MicroLabel (moved to ShareScene in commit 3) - "Entire invoice encoded in URL" pill repositioned to frames 130-180 * fix(video): MicroLabel + Caption stronger neon glow + bigger padding MicroLabel pill: padding 10/16 → 16/28, border opacity 0.3 → 0.6, boxShadow gains dual neon halo (24px + 48px violet) for visibility against zinc-950 background. Caption pill: border opacity 0.4 → 0.7, padding 14/28 → 18/36, boxShadow gains dual neon halo (32px + 64px violet) to match visual weight of the larger pill. * fix(video): S2 modal 512w + 4x longer URL + match real ShareModal layout + InvoiceSummary - ShareScene: modal width 760 → 512, recentered (left: width/2-256) - URL hash payload extended to ~560 chars so LinkTab visibly truncates - Header padding 24/32 → 16/24 to match real ShareModal px-6 pt-6 - Added InvoiceSummary block between header and tabs (real widget component, pure presentational — no client-side hooks, safe for Remotion) - Tabs wrapper padding 0/32/32 → 0/24/24 (px-6 pb-6); removed mb-4 on TabsList - Added "Link contains everything" MicroLabel at y=14% frames 70-150 (moved from S1 CreateScene per plan) - share-modal/index.ts: exported InvoiceSummary from public API * fix(video): S3 panel vertical-center + faster Magic Dust + longer paid hold - Panel positioning: top fixed-px → top:"50%" + translate(0,-50%) for true vertical centering; removed PANEL_HEIGHT constant - Timeline compressed (round 3): MAGIC_DUST_HIGHLIGHT 240 → 180 MAGIC_DUST_PEAK_END 360 → 300 CONFIRMING 360 → 300 SUCCESS 480 → 390 - Caption "Cryptographic receipt": startAt 240→180, endAt 360→300 - MicroLabel "Micro-amount added": startAt 240→180, endAt 330→270 - MicroLabel "Verified on-chain": startAt 990→420, endAt 1050→500 (fixes pre-existing bug: 990 was outside scene bounds) - Toast "Confirming on-chain": startAt 360→300 - Toast "Payment received": startAt 480→390 * fix(video): S1 reorder fields (Invoice No + Dates first) + delay scroll start Invoice No appears at frame 10, Dates at frame 25 — before Your Name (35) so viewer understands the document type before the form fills out. Scroll keyframes shifted from [0,40,80,120] to [10,50,90,130] so the form holds still while the "is the URL" cross-fade from S0 completes. focusedField returns undefined before FROM_START=35 (Invoice No / Dates are not part of InvoiceFormViewProps focusedField enum). MicroLabel hints shifted: "Filling out" 0-45 → 5-55, "Encoded in URL" 130-180 → 140-190 to align with BUTTON_VISIBLE delay. * fix(video): S1 lock form Card height + always-on glow border Card gets explicit height: height * 0.88 so the form panel never expands beyond its bounds regardless of InvoiceFormView content. Glow border changed from conditional (only when buttonGlowOpacity > 0) to always-rendered: baseGlow=0.25 gives ~0.15 opacity from frame 0, then pulseDelta adds 0.05-0.4 after BUTTON_VISIBLE=130. This eliminates the jarring pop-in that was visible in p6 render. * fix(video): caption + microlabel timing — S2 + S4 S2 (ShareScene): - Caption "No signup" delayed 25fr so it clears the cross-fade entrance. - MicroLabel order swapped: "Link contains everything" now leads (5-65, y=84%), "Hash fragment" follows at top (70-130, y=14%), "Same invoice" closes (95-170, y=84%) — windows don't overlap (65 < 95 for bottom slot). S4 (ThesisOutroScene): - MicroLabel shifted 30→10 / 100→75 so it shows during scene entrance and fades before the voidpay.xyz pill enters, eliminating the empty tail. * fix(video): S1 timeline shift — scroll stops at 5s, button press at 7s, merge URL captions Round 5: pull field-reveal constants earlier (all fields by fr 125), scroll finishes at fr 80 (mp4 5.000s), button press scale feedback at fr 140 (mp4 7.000s). Relocate "No signup" MicroLabel from S2 Caption → S1 MicroLabel (fr 26–65). Merge two URL labels into one in S2. S1 duration 306→170, thesisOutro 150→286. Recompute MAGIC_DUST_PEAK_FRAME 876→680. * fix(video): S1 round-6 — compress field timing + scroll ends at mp4 04.133s * fix(video): S1 round-6 — sequential Captions (No backend → No signup) + persistent No login MicroLabel * fix(video): S1 round-6 — Generate button overlay (active state + button-only press-scale) * refactor(payment): extract SmartPayButtonView for headless reuse (Container/View split) * fix(video): S3 round-6 — 6-phase CTA flow with per-transition press-scale + Verified label top * fix(video): S2 round-6 — persistent No login MicroLabel across S1→S2 cross-fade * fix(video): S1 round-7 — 1s pause before scroll + less aggressive offsets * fix(video): S1 round-7 — real GenerateButton inside scroll (replaces overlay; matches production form) * fix(video): S1+S2 round-7 — No login bottom-left + QR shortened to last 1s of S2 * fix(video): S3 round-7 — kill reorg-blink + Cryptographic receipt at 25s * fix(video): S4 round-7 — remove leftover No-login MicroLabel (moved to S1+S2 in round 6) * fix(video): round-8 — redistribute create=260 / thesisOutro=196 + recompute MAGIC_DUST_PEAK_FRAME=770 * fix(video): S1 round-8 — +60fr sympathetic shift (2s pause-before-fill) + scroll slowed to 54fr motion * fix(video): S2 round-8 — Same-invoice MicroLabel synced to QR display window * fix(video): S3 round-8 — Verified-onchain MicroLabel bottom-left (no collision with Cryptographic-receipt Caption) * chore(video): scenes.ts round-9a durations + ThesisHook beat shift -12fr - SCENE_DURATIONS: create 260→320, share 240→260, pay 510→575, thesisOutro 196→175 - TOTAL_DURATION stays 1350 (sum 1420 - 80 crossfades = 1340 visible; 10fr black tail) - MAGIC_DUST_PEAK_FRAME: 770→860 (S3 starts at global 610; peak midpoint S-local 250) - MAGIC_DUST_PEAK_HOLD stays 120 (creative-brief §8) - ThesisHook beats shifted -12fr: beat1 fades in 0-18 (was 12-30), beat2 fades in 30-48 (was 42-60) * feat(video): CreateScene round-9a — 2× cascade, post-fill paper, button-after-paper, remove messages - Field cascade widened: INVOICE_NO_APPEAR=65, TOKEN_APPEAR=179, FILL_COMPLETE=195 (+130fr span) - InvoicePaper now gated on PAPER_APPEAR=200 (post-fill), violet accent pulse 230→280 - BUTTON_VISIBLE=280 (after paper hold), PRESS_START=290, PRESS_END=307 - Glow pulse active throughout fill (INVOICE_NO_APPEAR→BUTTON_VISIBLE), settles to calm halo after - Removed Caption and MicroLabel imports + JSX (round-9a: no messages in S1) - GenerateButton stays production component; will swap to GenerateButtonView in C6 * feat(video): ShareScene round-9a — Link 80fr read + 110fr QR + remove messages + Copy single-fire - COPY_CLICK_FRAME: 60→110 (gives 80fr Link-tab idle read window before copy fires) - QR_TAB_FROM_FRAME: 210→150 (expands QR window 30fr→110fr / 3.667s) - Removed MicroLabel import + all 4 MicroLabel JSX nodes (round-9a: no messages in S2) - Copy double-fire: Fix B chosen — copied boolean flip is stable per-frame; CopyOverlay motion.div animate restarts each Remotion frame but palette swap is instantaneous so visual is acceptable for p12 preview; production snapshot unaffected * feat(video): PayScene round-9a — connecting/switching states, reorg progress restored, remove messages - New phase constants: PRESS_CONNECT=58, PHASE_CONNECTING=65, PHASE_WRONG_NETWORK=95, PRESS_SWITCH=153, PHASE_SWITCHING=160, PHASE_READY=190, PRESS_PAY=268, PHASE_SENDING=275, PHASE_CONFIRMING=365, SUCCESS=455 - stepAt() extended: returns idle:connecting (65-95) and idle:switching (160-190) - ctaPressTriggerFrame extended: handles connecting→PRESS_CONNECT, switching→PRESS_SWITCH - Magic Dust anchors: MAGIC_DUST_HIGHLIGHT=170, MAGIC_DUST_PEAK_END=310 - Reorg progress restored: RemotionPaidConfirmationProgress fork (no framer-motion) rendered as overlay during step===confirming; production widget stays byte-identical - Toast anchors re-anchored to new phase frames (58/153/273/365/455) - Removed Caption + MicroLabel imports + JSX (round-9a: no messages in S3) - KEEP RemotionFakeToast (spec requirement) * feat(payment): extend IdleSubState with connecting/switching for video v2 round-9a - IdleSubState widened: 'disconnected' | 'connecting' | 'wrong-network' | 'switching' | 'ready' - Production Container (SmartPayButton) unaffected: deriveIdleSubState() still returns only the 3 production values; new states are Remotion-only transitions in PayScene stepAt() - SmartPayButton snapshot tests: 29/29 unchanged (production Container does not emit new states) - Type-check: clean (production code uses subset of wider type) * feat(invoice-form): extract GenerateButtonView for Remotion compatibility (round-9a) - GenerateButtonView: presentational component with hoverState/pressState props for Remotion frame-driven hover/press simulation (no framer-motion, no CSS transitions) - GenerateButton (Container): delegates to GenerateButtonView; production toast fallback preserved; snapshot test 2/2 byte-identical unchanged - Exported from ui/sections/index.ts and widgets/invoice-form/index.ts (FSD public API) - CreateScene: swapped GenerateButton → GenerateButtonView with prop-driven states (hoverState: BUTTON_VISIBLE→PRESS_START, pressState: PRESS_START→PRESS_END) * fix(video): CreateScene round-9a-patch1 — scroll stops at 8.6s + button mount earlier B1: SCROLL_FRAMES end 200 → 188 so scroll stops before empty space below last field. B2: Button mounts at FILL_COMPLETE (195) instead of BUTTON_VISIBLE (280) so user sees the GenerateButton during scroll; hover halo still gates on BUTTON_VISIBLE (280). * fix(video): PayScene round-9a-patch1 — canonical PaymentStep + widened CTA gate + toast retiming B3: stepAt() returns step:'connecting'/'switching' (PaymentStep canonical) so getButtonLabel routes correctly instead of falling through to default 'Pay'. B4: auto-fixed — getProgress() now returns 0.25/0.45 for connecting/switching steps. B5: T1 toast startAt 58→95 (wrong-network activates), T2 153→190 (ready activates) — toasts fire after transition completes, not at press moment. B6: CTA render gate widened from (idle||sending) to (!=confirming && !=success) so SmartPayButtonView renders during connecting/switching/sending phases. * chore(video): scenes.ts round-9a-patch2 — durations rebalance + MAGIC_DUST_PEAK_FRAME=940 create 320→350 (+30fr, C4 generating hold) share 260→300 (+40fr, C5 extended copy hold) thesisOutro 175→105 (-70fr, funds S1+S2 per Ignat directive) pay 575 unchanged (C7 is internal reshuffle only) TOTAL_DURATION=1350 locked; black tail=10fr preserved. MAGIC_DUST_PEAK_FRAME: 860→940 (S3 single-press model, S-local peak midpoint 260 → global 940) * feat(video): CreateScene round-9a-patch2 — always-mounted button + scroll trim + magic dust toggle + generating state + draft paper C1: Remove FILL_COMPLETE mount gate — button always rendered in scroll content; canGenerate=false until FILL_COMPLETE (disabled visual until form fills). C2: SCROLL_OFFSETS final -420 → -360; proportional intermediate keyframes updated (0, -120, -240, -360). Final endpoint to be verified via still at frame 258. C3: magicDustEnabled: frame >= MAGIC_DUST_TOGGLE_FRAME (200) — toggle animates off→on after TOKEN_APPEAR=179. C4: isGenerating={frame >= PRESS_END} — spinner + "Generating…" visible 307→350 (scene end). C6: Path A — status="draft" (valid InvoicePaperStatus value; no production widget fork needed). * feat(video): ShareScene round-9a-patch2 — extended copied state hold (80fr/2.667s feedback) C5: QR_TAB_FROM_FRAME 150→190. COPY_CLICK_FRAME stays 110. Copied state now visible frames 120-190 (70fr / 2.333s) before QR tab switches. S2 duration funded the extra 40fr (260→300) without compressing QR window. * feat(video): PayScene round-9a-patch2 — single-press model + retimed phases + magic dust 940 + toasts at transitions C7: Remove PRESS_SWITCH, PRESS_PAY, PHASE_WRONG_NETWORK, PHASE_READY. Phase walk: disconnected(0) → press(48) → connecting(50) → switching(130) → sending(200) → confirming(310) → success(440). ctaPressTriggerFrame: single PRESS_CONNECT=48 only; pressScale clamps after +7fr. Magic Dust: HIGHLIGHT=180, PEAK_END=320 (120fr peak straddles sending→confirming). Toasts: T1=130, T2=200, T3=205+stackOffset=1 (staggered from T2 to avoid collision), T4=310, T5=440. Snapshot tests: 237/237 payment, 56/56 invoice-form, 157/157 payment-panel — all byte-identical. * fix(video): PayScene round-9a-patch3 — remove redundant Sending toast (D1) * fix(video): RemotionFakeToast round-9a-patch3 — below-panel anchor aligns to panel LEFT edge (D2) * fix(video): PayScene round-9a-patch3 — InvoicePaper flips to paid at confirming (D3) * fix(video): RemotionFakeToast revert below-panel anchor to right-edge alignment (D2 reverted) * feat(video): add VoidPayDemo-9x16 primary composition + RemotionAuroraText component Round 9c C1+C2: add portrait 1080×1920 composition as primary (phone-first GTM per L1). VoidPayDemo-16x9 becomes secondary with comment noting round 9d will re-derive layout. RemotionAuroraText: frame-driven gradient text (no CSS animations) matching landing aurora colours — violet-500/indigo-500/purple-500, 5-stop 200% sweep, deterministic. * feat(video): ThesisHookScene + ThesisOutroScene aurora-gradient thesis (round 9c L4) C3: ThesisHookScene wraps both beats in RemotionAuroraText with phaseFrames=30 stagger. Adaptive fontSize: 84px portrait / 72px landscape. C4: ThesisOutroScene wraps "Cryptographic receipts." in RemotionAuroraText; "Not audit logs." stays dim white for visual hierarchy. url-pill "voidpay" gets gradient with phaseFrames=45. Adaptive heroFontSize 110/96, urlFontSize 42/36 for portrait. * feat(video): ShareScene full-bleed paper backdrop + tab slide (round 9c L2 L5) * feat(video): PayScene bottom-sheet panel + paper backdrop + pre-CTA exit (round 9c L2 L3 L6) * feat(video): CreateScene portrait re-layout (round 9c L7) * feat(video): ShareScene floating-center modal + solid bg (round 9c-β1 β3) * feat(video): PayScene floating-center panel + revised exit (round 9c-β1 β3) * feat(video): CreateScene paper backdrop + form vertical dominance (round 9c-β2 β3 β4) * feat(video): ThesisHookScene + ThesisOutroScene NetworkBackground (round 9c-β6) * feat(video): CreateScene true-center form + scale + single neon (round 9c-γ1 γ2 γ3) * feat(video): ShareScene true-center modal (round 9c-γ4) * feat(video): PayScene true-center panel + 3× paper-alone window (round 9c-γ4 γ6) * feat(video): RemotionFakeToast top-center portrait positioning (round 9c-γ5) * fix(video): round 9c-δ — form z-stack + tail bg + ts unused-vars cleanup - CreateScene: add zIndex: 2 to form Card so it renders above PaperBackdrop (z=1) - VoidPayDemo: set AbsoluteFill background to #000 so fade() composites against black (no white tail frames 1336-1349) - ShareScene + PayScene: remove unused width/height from useVideoConfig() destructure (TS6133) * feat(video): CreateScene drop transform-scale + font-size CSS + right-pad (round 9c-ε1) * feat(video): ShareScene RemotionLinkTab fork + Copy Link primary + drop QR tab (round 9c-ε2) * feat(video): ThesisOutroScene delay text entrance 12fr (round 9c-ε3) * feat(video): RemotionFakeToast bigger text + hold (round 9c-ε4) * feat(video): PayScene panel size reduction (round 9c-ε5) * feat(video): CreateScene paper backdrop scrim (round 9c-ε6) * fix(video): CreateScene overflow axis split (round 9c-ζ1, fix Iris BLOCKER) overflowX:visible preserves right-column TOTAL visibility (ε1 intent). overflowY:hidden clips form content at Card bottom so "Generate Invoice Link" button and "Generating..." state are no longer clipped at the viewport bottom (f280/f410). Fixes ε1 regression introduced in round 9c-ε. * fix(video): ShareScene modal vertical balance + "URL = invoice." caption (round 9c-ζ3+ζ4) ζ3: Shift modal top 50%→48% — paper mass creates visual top-heaviness; 48% places modal in the visual center of the dark space below the paper. Spring (damping:200) confirmed settled by f20, no oscillation at f480. ζ4: Add Caption "URL = invoice." (top, startAt=60, endAt=250, fontSize=38). Content Anchor #3 — names the architectural fact that the URL IS the invoice, not a link to one stored on a server. Appears after modal lands, persists through Copy click at ~f120, fades before quiet hold. * feat(video): PayScene "Not our servers." caption (round 9c-ζ5) Add Caption "Not our servers." (top, startAt=460, fontSize=38, no endAt). Content Anchor #1 — enters 20fr after T4 "Payment received" toast fires (f440), reframing the confirmed payment as a privacy proof: the chain confirmed it, not VoidPay servers. Persists to scene end through paid invoice paper reveal window. * feat(video): HintBadge component for inline annotations Spring fade-in (smooth config) + linear fade-out, two variants: ghost (violet text only) and arrow (violet text + dark pill). API mirrors Caption.tsx — startAt/endAt frame window, absolute style prop for caller-controlled placement. * feat(video): CreateScene η1+η2+η6+η7 (No signup caption + 3 hints) η1: Caption "No signup." bottom position frames 280–340 (Spark Beat 11, button reveal moment — answers viewer's account question). η2: HintBadge "+ 0.000042 ← magic dust" arrow variant frames 220–280 (R1: startAt=220, 20fr after PAPER_APPEAR=200 to avoid paper-reveal collision). η6: HintBadge "any address, no KYC" arrow variant frames 115–175 (near wallet field during recipient typewriter cascade). η7: HintBadge "auto-generated" ghost variant frames 65–95 (near Invoice No field, early cascade appearance). * feat(video): PayScene η3+η4 (Open link Pay caption + Magic Dust hint) η3: Caption "Open link. Pay." top position frames 15–80 (Spark Beat 18, scene framing before Connect Wallet press; startAt=15 per R3 to let cardScale spring animate before caption enters). η4: HintBadge "unique micro-amount ← payment ID" arrow variant frames 210–300 (during MAGIC_DUST_HIGHLIGHT violet glow window, below panel centered; exits before T3 Confirming toast at 310). * feat(video): ShareScene η5 (invoice data hint on URL hash field) η5: HintBadge "invoice data →" ghost variant frames 80–160 (Spark Beat 15; R2: startAt=80, 20fr after ζ4 "URL = invoice." caption enters at 60, avoids 3-layer density peak; exits at 160, before quiet hold at 250). Positioned bottom-right of permalink box pointing at the hash fragment, reinforcing the ζ4 caption's "URL = invoice" thesis. * feat(video): HintBadge readability bump (round 9c-θ3) Default fontSize 15→20px (floor for 9:16 portrait phone playback per ui-ux-pro-max mobile-first rules). Arrow variant: darker bg (0.75→0.88 opacity), stronger violet border (0.35→0.55), proportional padding (4px 10px→6px 14px). Font weight 500→600. Color rgba(139,92,246,0.9)→ rgba(167,139,250,1) — full saturation for WCAG contrast floor. * feat(video): RemotionFakeToast bottom positioning (round 9c-θ7) Portrait toasts move from top-center to bottom-center. Top zone is now exclusively reserved for Caption.tsx pills. Slide direction reversed: enters from below (+100px), exits drifting down (+60px). Landscape behavior unchanged (right-side slide). Cross-impact: η1 and η4 hints repositioned in their respective scenes. * feat(video): RemotionLinkTab restore production density (round 9c-θ5) Reverts ε2 simplification (Copy Link only). Restores full production ShareModal LinkTab density: color-coded permalink (protocol/domain/path/ hash color-coded matching production), Copy Link primary CTA, 3-col social share row (Telegram/Twitter/Email with production color scheme), OG toggle (amber), Privacy by design note. Adds ogEnabled prop for narrative OG state. No animate-* Tailwind, no browser hooks — Remotion render path safe. * feat(video): CreateScene θ1+θ2+θ4 — header, width, paper centering + η1 reposition (round 9c) θ1: Add 'Invoice Details' header at top of form Card matching production InvoiceFormView page header (violet 'Invoice' + white 'Details', 22px bold, divider border below). θ2: Form width reduced from min(800,74%) to min(560,52%) — ~67% of prior width. Base font-size bumped 20px→26px proportionally to preserve visual mass per field. Sub-label override floor raised 16px→18px. Form now reads as focused central column with breathing room for paper backdrop on both sides. θ4: PaperBackdrop vertical centering balanced — paper now centered in [80px, height-100px] band (caption zone top, toast zone bottom) so top margin equals bottom margin. η1 cross-impact (θ7): 'No signup.' caption moved bottom→top. Bottom zone is now reserved for toasts after θ7 move. * feat(video): PayScene θ6 panel +1.5× + η4 reposition (round 9c) θ6: PANEL_WIDTH 520→780 (1.5× per spec). Reverts ε5 reduction. Drops ×0.92 scale wrapper — panel now renders at full production size. Panel occupies ~72% of 1080 viewport matching production PaymentPanel proportions. η4 cross-impact (θ7): 'unique micro-amount ← payment ID' hint moved from bottom:28% to top:80. bottom zone now has toasts (θ7). Top zone clear at f210-300 — η3 exited at f80, ζ5 starts at f460. fontSize bumped 14→20 to match θ3 HintBadge default floor. * feat(video): ShareScene θ5 modal density + η5 reposition (round 9c) θ5: Modal width 512→600 to accommodate full production density. Adds tab bar (Link/QR Code) above RemotionLinkTab — Link tab active before COPY_CLICK_FRAME (f110), QR Code tab active after, demonstrating tab-switching in scene. Reverts ε2 'info overload' simplification per user override (density wins). η5 cross-impact: 'invoice data →' hint repositioned top:28→top:8 to account for wider modal. fontSize 13→15 (above legibility floor). * feat(video): HintBadge text ×2 (round 9c-ι4) Default fontSize 20→40px, arrow padding 6px 14px→12px 28px. Callers with layout constraints pass explicit override (e.g. η5=24px). * feat(video): CreateScene form internals ×1.3 (round 9c-ι1) + η hint bump Base fontSize 26→34px, sub-label override 18→23px, Invoice Details header 22→29px with proportional margin/padding. η7/η6/η2 hint fontSize 14→28px (×2 per ι4 rule). Card outer width unchanged at θ2 560px. * feat(video): RemotionLinkTab modal internals ×1.5 (round 9c-ι2) + η5 adjustment RemotionLinkTab: all text/spacing/heights ×1.5 (Permalink label 11→17px, URL box 11→17px, Copy Link button 14→21px h52→78, social row 12→18px h40→60, OG/privacy 11-12→17-18px). ShareScene: modal width 600→660px (+10% to absorb scaling), header 20→30px, subheader 14→21px, tab height 34→44px fontSize 13→20px, section paddings scaled. η5 exempted from ×2: 15→24px (×1.6) — right:12 top:8 position inside permalink wrapper cannot fit 30px without overflowing above bounds. * feat(video): PayScene panel internals scaled (round 9c-ι3) + η4 ×2 Panel wrapper fontSize:24px drives em-cascade into PaymentPanel internals (24px = 1.5× browser default 16px). Panel outer width unchanged at θ6's 780px. η4 hint fontSize 20→40px (×2 per ι4), top nudged 80→90px to avoid edge clip. * fix(video): F1 ThesisHook cross-fade window symmetric (κ-1) Widen beat1 fade-out from [30,36] to [30,48] so it matches beat2's fade-in window. At f39 both beats are ~50%, producing a true symmetric cross-fade. Fixes RC-2 BLOCKER from p21 diff-report. * Revert "fix(video): F1 ThesisHook cross-fade window symmetric (κ-1)" This reverts commit a35ac2026571b14b84c163ab3ae66b7a26ded5b7. * fix(payment-panel): voice-gate compliant CTA copy (κ-1 RC-3) Changes success-state CTA from "Create your own invoice with VoidPay" to "Create an invoice" per voice-guide §"We Don't Say" (no possessive, no brand-drop). Conversion impact expected neutral; Spark to review post-deploy. * fix(video): demo invoice Bill-To matches form (κ-2 RC-5) Paper Bill-To now reads 'Acme Corp' to match the form's typed value, fixing the F4→F12 data inconsistency reported in the p21 diff. * fix(video): PayScene 5-beat timing reshuffle (κ-3 RC-1) Phase window changes (S3-local frames): | Phase | Old window | New window | Delta | |------------|-------------|-------------|-------| | idle | 0–50 | 0–90 | +40fr | | PRESS_CONNECT | 48 | 85 | +37fr | | connecting | 50–130 | 90–170 | +40fr | | switching | 130–200 | 170–240 | +40fr | | sending | 200–310 | 240–340 | +40fr | | confirming | 310–440 | 340–470 | +30fr | | success | 440–575 | 470–575 | +30fr | | MAGIC_DUST_HIGHLIGHT | 180 | 240 | +60fr | | MAGIC_DUST_PEAK_END | 320 | 390 | +70fr | | PANEL_EXIT | 495–515 | 525–545 | +30fr | Key fixes: - Idle window 50→90fr: B1 Connect Wallet beat now visible through crossfade entry - paperPaid: confirming||success → success only: B4 (confirming) shows pending paper + progress bar, visually distinct from B5 (paid paper + success panel) - All captions/hints/toasts shifted to match new phase boundaries: ε3 endAt 80→88, η4 startAt/endAt 210-300→255-345, ζ5 startAt 460→490 T1 130→170, T2 200→240, T3 310→340 (hold 90→140), T4 440→470 - S3 total duration 575fr unchanged; TOTAL_DURATION 1350 unchanged * fix(video): hint repositioning — η6 + η2 + η5 (κ-4 RC-4) η6: move "any address, no KYC" above wallet field label (was at 0.28×height, overlapping address text; now 0.16×height in clear annotation zone) η2: move "+ 0.000042 ← magic dust" to right-anchored outside form card (was 0.30×width inside form pointing at fields; now right:16 with ← pointing at paper TOTAL column) η5: move "invoice data →" outside Card overflow:hidden clip (was inside relative div at right:12 top:8 — never rendered; now AbsoluteFill-level at permalink box zone, calc(48%-90px)) * fix(video): QR tab body sync (κ-5 RC-6) Tab indicator flipped to QR Code at COPY_CLICK_FRAME but body always rendered RemotionLinkTab (permalink view) — no RemotionQRTab existed. Fix: create RemotionQRTab (QRCodeSVG + scan hint + Download QR button, production-parity) and swap body in sync with tab indicator at the same frame. Copied! flash fires 10fr before swap so Link tab shows affordance before QR transition. * feat(video): unified NetworkBackground orb layer (import point #1) Create NetworkBackgroundLayer.tsx with Mocks v2 .nb-orb formula (inline styles, absolute positioning, Remotion-safe). Mount in all 5 scenes: strong variant (55% orbs, blur 56px) for Hook/Outro, soft variant (50% orbs, blur 48px) for Create/Share/Pay content scenes. * feat(video): import F1 thesis-hook hero layout + typography (#2) Replace single-line cross-fade with Mocks v2 hero structure: VoidPay mono pre-line, two-line H1 (dimmed "The invoice" + aurora "is the URL."), and sub-text. Beat timing (0-18/30-48) unchanged; layout now uses flex-column centering per mock .hero spec. Font sizes ×3 of mock's 360px design viewport. * refactor(video): rebuild HintBadge with v2 design tokens (#3, style only) Replace ghost/arrow pill with Mocks v2 .hint spec: zinc-900 background, violet-700 border, triple box-shadow, leading violet dot with glow, inline →/← arrow spans in violet-300. Font sizes proportional to fontSize prop (mock values ×3 for 1080 viewport). Variant prop kept for API compat. * chore(video): reposition hints per Mocks v2 anchors (#3, positions) Switch all hint positions from form-relative px math to percentage anchors matching mock's 360×640 design viewport. Update hint copy to canonical Mocks v2 text: η7 "No DB → link is the data", η6 "Your wallet. No KYC. No bank.", η2 "Magic dust → unique payment ID", η5 "invoice data → in the hash", η4 "unique micro-amount ← payment ID". * feat(video): apply Mocks v2 sizing/typography to CreateScene form (#4) Card background rgba(14,14,19,0.95), border rgba(63,63,70,0.5), border-radius 12px, shadow 0 16px 50px rgba(0,0,0,0.5) — matching mock .form spec. Header updated to "/ Create invoice" with Geist Mono slash prefix (zinc-500) + bold sans title per mock .form .h pattern. * feat(video): paper blur+dim when modal/CTA foregrounded (#5) CreateScene F5 (Generate pressed): paper dims 0.65→0.4, blur 0→0.5px over 8fr ramp starting at PRESS_START. ShareScene F6-F8: paper dimOpacity 0.35→0.3, blurPx 1.5→2.0 across COPY_CLICK_FRAME. PayScene paper stays at 1.0 (paper is co-equal in S3 per spec §5 table). * feat(video): browser chrome (BrowserChrome component) for PayScene (#6) New BrowserChrome.tsx renders mock .chrome spec: dark bar at top:0, traffic-light dots (red/amber/green), URL pill with lock emoji + violet host + zinc path. Mounts across full S3 duration with 20fr opacity ramp. Also includes WalletPill.tsx stub (C7) — both needed in PayScene import. * refactor(video): align Caption to v2 design + emerald success variant (#8) Rebuild Caption with Mocks v2 .caption spec: rgba(20,20,27,0.85) bg, backdrop-filter blur(8px), violet-400/45 border, 0 0 24px glow, top anchored at 114px (38px mock × 3). Add emerald variant for success state — emerald-400 text/border/shadow. Wire PayScene "Not our servers." caption to emerald variant. * feat(video): rebuild ThesisOutro with v2 hero + center-block layout (#9) Replace "Cryptographic receipts / Not audit logs" copy with Mocks v2 F13 structure: mono pre-line "No accounts · no DB · no servers", full aurora h1 "The invoice\nis the URL.", sub "Open. Pay. Done.", voidpay.xyz wordmark. All 4 elements form one centered flex-column block — drops margin-top:auto on wordmark per Ignat centering directive. * refactor(video): center-anchoring per Mocks v2 (#10, partial) PayScene: paper sits at top:64px below browser chrome (CHROME_HEIGHT constant), centered in remaining viewport. ShareScene: paper backdrop uses true vertical center (height-scaledH)/2 — was biased upward by -80px to clear modal at bottom; modal now uses top:50% transform per Mocks v2 .paper anchor. CreateScene PaperBackdrop deferred — atlas exhausted context before applying same true-center pass. Visual diff will reveal whether it needs the same treatment or stays as-is. * fix(video): F1 thesis hook — full phrase visible from frame 0 (drop cross-fade) * feat(video): RemotionInvoiceFormSkin — internal form styles from Mocks v2 * feat(video): RemotionShareModalSkin — modal fonts/sizes from Mocks v2 * feat(video): RemotionPaymentPanelSkin — panel fonts/sizes from Mocks v2 * fix(video): PayScene paper blurred while panel foreground; sharp at F12 paper-alone (#6 corrected) * chore(video): re-render p24 assets (post-style-internal-import) * fix(video): F1 muted "The invoice" text more visible (opacity 0.35 → 0.50) * refactor(video): revert form skin — production InvoiceFormView with surgical width/padding from Mocks v2 * refactor(video): revert share modal skin — production component with width/padding + F8 text sizes * refactor(video): revert payment panel skin — production PaymentPanel with width/padding + F10 text sizes (spinner kept at frame*8) * chore(video): re-render p25 assets (post-skin-revert + surgical overrides) * fix(video): confirming beat outside panel + dust halo + panel exit + voice-gate (Phase 1-2) C3 (F1.A2): RemotionPaidConfirmationProgress rendered outside PaymentPanel — it was wired as children but PaymentPanel.children only renders when isPending=true; during confirming isPaid=true so children never appeared. Now overlaid below panel. C4 (F1.C1): Magic dust halo replaced with anchored bottom-right ellipse (blur 14px) per Mocks v2 spec. Text-shadow injection on dust digits via .remotion-dust-glow style. C6 (F2.A4): panelExitOpacity window shifted 525-545 → 505-525 (20fr earlier), giving paper-alone window 525-575 = 50fr (1.67s) vs previous 30fr. C7 (F2.D1): CreateYourOwnCta link suppressed via CSS (.remotion-pay-panel a[href="/create"]) — voice-gate violation (self-referential CTA in a product demo video). C13 (F4.3): .text-xs floor raised to 24px inside .remotion-pay-panel — payment widget secondary text was sub-10px illegible at 9:16 mobile preview scale. * fix(video): F7 sub-line 24px + F8→F9 tab swap cross-fade 8fr (Phase 4 iris polish) C12 (F4.2): InvoiceSummary secondary text (.text-xs) forced to 24px inside .remotion-summary-override wrapper — was rendering ~9px illegible at 9:16 mobile scale. Color bump zinc-500 → zinc-400 (#a1a1aa) for better contrast. C14 (F4.4): Link→QR tab body transition cross-fades over 8fr using interpolate opacity drivers (linkTabOpacity / qrTabOpacity). Previously hard-cut at COPY_CLICK_FRAME, now reads as a natural UI interaction. Tab indicator retains crisp swap (no blur on chrome). * chore(video): re-render p26 assets (followup BLOCKER pack + iris polish) * style(video): ShareScene Link tab dominant timing (COPY_CLICK_FRAME 110→200) - COPY_CLICK_FRAME: 110 → 200 (Link tab dominant 0-208 ~6.9s, QR demonstrative 200-300 ~3.3s) - Updated comment to reflect new pacing rationale (Ignat 2026-05-11) - Caption "URL = invoice." endAt: 250 → 290 (lingers ~1.3s into QR tab, reinforcing URL=invoice as viewer sees QR) - TAB_CROSSFADE_DURATION=8 unchanged - PaperBackdrop (T3c) true-center untouched — canonical reference for atlas-A/C * style(video): CreateScene Tailwind cascade ×2 + paper true-center (Mocks v2) * refactor(video): PayScene cascade ×2 + flat panel (no shadow/border) + paper true-center T4a: Replace minimal CSS block with full Tailwind ×2 cascade scoped to .remotion-pay-panel (text-xs→text-4xl, h-7→h-11, w-3→w-6, padding, gap, border-radius). Drop outer fontSize:"24px" → fontSize:"inherit". Keep a[href="/create"] display:none (voice-gate CTA suppression). T4b: Remove boxShadow + zinc border from panel div wrapper. PayPanel becomes flat modal on dark bg — matches Image 3 mock per Ignat 2026-05-11 17:43. T4c: PaperBackdrop true-center alignment — replace chrome-offset formula with canonical top = (height - scaledH) / 2 (identical to ShareScene). Drop unused CHROME_HEIGHT constant. * style(video): CreateScene HintBadge chips fontSize 28→34 (×1.2 vs body cascade) * style(video): Thesis intro/outro text colors match landing Hero (D1+D11) Split H1 rendering in ThesisHookScene and ThesisOutroScene: - "The invoice" → bold white (#FFFFFF), was muted grey/aurora - "is the URL." → RemotionAuroraText violet aurora (unchanged in Hook, fixed in Outro) * style(video): PayScene cascade strict matches production sizes (D8) Add h-12/h-14 for Connect Wallet button (production uses h-14 via Button size="lg"), w-11/h-11 for minimize icon, px-4/px-6/py-0.5/pt-5/pr-12, gap-2.5/gap-0.5, space-y-2/space-y-4 vertical rhythm, rounded/rounded-full, and a shadow/border strip on [data-testid="payment-panel"] to cancel PaymentPanel's own shadow-[...] and conditional border-emerald classes. * style(video): CreateScene header matches production InvoiceFormView (D2) Replace "/ Create invoice" (grey slash prefix) with violet "Invoice" + white " Details" to match production CreateWorkspace header pattern. Remove now-unused FONT_MONO import from CreateScene. * fix(video): PayScene flat panel + drop reorg overlay (D9+D10) D9: add [data-testid="payment-panel"] box-shadow/border strip in cascade to cancel PaymentPanel's own shadow-[...] and isPaid border-emerald class. D10: delete "Protecting against chain reorgs" JSX overlay block (step=== 'confirming'), remove unused RemotionPaidConfirmationProgress import and orphaned confirmingProgress interpolate declaration. Component source file RemotionPaidConfirmationProgress.tsx is left untouched. * style(video): ShareScene cascade + Copy button violet + gaps match production (D6+D7) D6: extend remotion-summary-override cascade to scale amount sum (text-base/lg→36px), network chip (text-xs→22px), inner padding/gap; add violet inset underline on active tab. D7: increase RemotionLinkTab section gap 21→30px for production-parity vertical spacing. Copy button violet gradient was already correct; gaps and amount sizing now match Image #13/#15. * fix(video): CreateScene date icons + extended scroll past Token & Network (D3+D5) Atlas-B leftover from round-9e Phase 1 — committed by Kai after atlas timeout during verification phase. Code passes type-check + lint clean. D3: SVG icons inside text-[10px] labels — cascade override 24x24px to match production calendar icons in date inputs. D5: SCROLL_FRAMES extend 188->195, SCROLL_OFFSETS extend -360->-900, drop height:100% + overflowY:hidden so cascade-2x form scrolls past Token & Network into Notes/Currency block. * fix(video): PayScene strip residual emerald border + gradient bar (D9 deeper) Atlas-D leftover from round-9e Phase 1 — committed by Kai after atlas timeout during verification phase. Code passes type-check + lint clean. D9 (deeper): T4b first pass cleared border/shadow but left: - Emerald conditional border (border-emerald-500/30 from PaymentPanel isPaid state) - Top gradient bar from PaymentPanel chrome Strip via: - Multiple-specificity .remotion-pay-panel selectors zeroing border-width/style/color - [data-testid=gradient-bar] display:none - Inner padding wrapper around <PaymentPanel> so outer overflow:hidden clips any conditional border flush to our rounded corners (padding moved from outer to inner to maintain visual inset while clipping panel's own border) * fix(video): HintBadge intrinsic width + chip anchor inside viewport (D4) Outer wrapper: add display:inline-block so right:-anchored chips shrink to content width instead of stretching to full block width. Inner chip: remove maxWidth:540px cap that caused nowrap text to visually overflow the pill border on longer chip texts (chip 3: 31 chars at 34px). All 3 chips now render with full pill border + text inside 1080px viewport. * style(video): ShareScene tabs underline-only style (D16) Remove grey background fill from active tab; keep violet inset box-shadow underline and bold text as the sole active indicator, matching production ShareModal tab design. * fix(video): PayScene drop outer dark frame (D17) Outer panel div had backgroundColor rgba(24,24,27,0.96) with padding:0, causing a visible dark border around PaymentPanel where the inner padding wrapper created a gap. Set outer backgroundColor to transparent — inner PaymentPanel provides its own background; viewer sees through to scene bg in any gap region. * fix(video): PayScene spinner rotation rate + drop extra Sending loader (D18+D19) D18: SmartPayButtonView's CSS animate-spin class is a real-time CSS animation (non-deterministic in Remotion). Override with animation:none + frame-driven rotate(frame*8deg) = 240deg/s = 1 rev/1.5s, matching production speed exactly. D19: Removed the extra centered overlay spinner that rendered during sending step inside PaymentPanel. The spinner was an absolute-positioned DIV overlapping the entire panel center. SmartPayButtonView already renders its own button-inline spinner for the sending state — the overlay was a duplicate. * style(video): PayScene Payment Successful block sizing (D20) Two cascade gaps caused mis-proportioned success state: 1. w-12 missing from width cascade — checkmark circle was 96px tall (h-12 overridden) but only 48px wide (Tailwind default 3rem). Added w-12: 96px to keep circle square. 2. CheckCheckIcon/CheckIcon use size={24} prop (absolute px, bypasses Tailwind cascade). Added .h-12.w-12 svg override to 48x48px so the icon fills the scaled container proportionally. * style(video): CreateScene icon cascade + unified scroll to Generate button (D15) Problem A: Icons using size={N} prop (CoinsIcon/FingerprintIcon/NetworkIcon/TokenIcon/ Share2Icon/ArrowRightIcon) rendered SVG width/height attributes directly — not caught by the Tailwind w-N/h-N class cascade. Added svg[width="N"] attribute selectors scaled ×2 for sizes 12/16/20/24px under .remotion-create-portrait. Problem B: Single master translateY interpolation extended with 5th keyframe [265, -2000] so the scroll completes before BUTTON_VISIBLE=280. Generate button fully in view at frame 270. No secondary translateY motions stacked. * style(video): PayScene Exact amount magic dust text size (D25) Add text-[9px] cascade entry (22px) to .remotion-pay-panel so MagicDustBadge "Exact amount: 250.000042 USDC" line renders at readable size. Previous cascade covered text-[10px]/text-[11px] but missed the [9px] class used in MagicDustBadge. * refactor(video): CreateScene unified scroll audit + endpoint clamp (D21) Audited all interpolate/translateY sources: confirmed single Y-motion driver (line 256). Previous -2000px endpoint overshot — Generate button scrolled off the top of the card before BUTTON_VISIBLE=280. Calibrated to -1100px so button lands flush at card bottom at f280. * style(video): ShareScene tabs + Copy button match production exactly (D24) Tabs: replace violet underline with dark card active state (bg-background zinc-900 pill + box-shadow), matching TabsTrigger data-[state=active] in production. Solid container opacity 0.6→1. Copy button: replace solid violet gradient with production Button variant=void — black bg, electric-violet/30 border, subtle violet glow shadow, with CopyOverlay radial gradient (violet idle / emerald success). * fix(video): CreateScene Generate spinner rotation rate normalize (D23) frame * 10 → frame * 8: 240 deg/s @ 30fps = 1.5s/rev, matching production animate-spin. Pattern consistent with PayScene D18 fix. D22: GenerateButtonView already uses production glow variant (bg-violet-600) with Share2Icon+ArrowRightIcon — cascade confirmed correct, no change needed. * feat(video): ShareScene landscape two-column layout (D12+D13+D14) Implements 16:9 two-column layout for ShareScene via useVideoConfig() width>height branch. Left column: InvoicePaper backdrop scaled to containerWidth=(width/2). Right column: Share modal capped at 640px. Caption stays at AbsoluteFill level spanning full viewport. Portrait (9:16) path unchanged — verified with stills at f450 and f600. * feat(video): CreateScene landscape two-column layout (D12+D13+D14) - isLandscape (width > height) gate renders separate AbsoluteFill with paper LEFT column and form RIGHT column (maxWidth 640px) - PaperBackdrop accepts columnWidth prop to scale within left half-viewport using 0.85× factor instead of 0.92× portrait full-width - HintBadges moved inside right-column wrapper for landscape; scaled to fontSize=22 to fit column proportions - Portrait (9x16) branch untouched — identical rendering verified at f150/f275 * feat(video): PayScene landscape two-column layout (D12+D13+D14) - useVideoConfig() isLandscape branch: paper LEFT, PaymentPanel RIGHT - BrowserChrome full-width top overlay over both columns - WalletPill anchored to full-viewport top-right (not column-confined) - PaperBackdrop: added containerWidth/containerHeight/offsetTop props for column-scoped layout - Magic dust halo pixel-anchored to paper totals area in left column - Portrait (9x16) render path unchanged — verified identical to p30 - panelCascadeStyle / panelBorderStrip / paymentPanelContent factored to shared variables (DRY) - PANEL_MAX_WIDTH=640, CHROME_HEIGHT=51 module constants * fix(video): ShareScene instant tab swap (no blink) (D27) TAB_CROSSFADE_DURATION 8→1: eliminates the mid-swap frame where both Link and QR tab bodies were at ~0.5 opacity simultaneously, causing the visible "blink". Tab indicator already swapped instantly via showQR binary; body now matches. * fix(video): CreateScene Magic Dust toggle visual render (D26) Switch thumb was rendering at mid-track (overlapping circles) because: 1. The ×2 portrait cascade scaled track to 80px but translate-x-5 stayed at 20px — thumb was mid-track instead of right edge. 2. CSS transition-transform on thumb was rendering at an intermediate state since Remotion renders static frames. Fix: add cascade rules under .remotion-create-portrait [role="switch"] to null all transitions and hard-set thumb position via translateX(44px) for aria-checked=true (80px track - 32px thumb - 4px inset = 44px). * fix(video): PayScene ALL spinner instances rotation rate normalize (D28) Extend frame-driven spinner cascade to cover all three Tailwind animate-spin variants used across PaymentPanel widget components: - motion-safe:animate-[spin_1.5s_linear_infinite] (SmartPayButtonView) - motion-safe:animate-spin (SecondaryActions, StatusBadge, PollingStatus) - animate-spin (fallback) All three now get animation:none + transform:rotate(frame*8deg) so no spinner runs at CSS keyframe speed in Remotion render. * style(video): PayScene magic dust + footer icons sizes (D29) Add svg[width="N"] cascade selectors for lucide icons rendered via size={N} prop (SVG attribute, not Tailwind class): - FingerprintIcon size={10} in MagicDustBadge → 20px - DownloadIcon/QrCodeIcon/FlagIcon size={12} in PanelFooter → 24px - Loader2Icon size={14} in PollingStatus → 28px Production-parity ratio: text-xs cascades to 24px; icons scale 2× to match. * fix(video): CreateScene Magic Dust toggle design refinement (D30) Root cause: w-10 track width was missing from portrait cascade (only w-3..w-6 covered), leaving the track at 40px wide × 40px tall — a square pill instead of the intended 2:1 ratio. Also fixes OFF-state translateX: was 2px (double-counting left-0.5 base inset), now 0px. Changes: - Add .w-10 → 80px to portrait cascade (track width now 80px × 40px) - OFF state: translateX(0px) — left-0.5 naturally provides 2px inset - ON state: translateX(44px) unchanged (80 - 32 - 2 - 2 = 44px math correct) * fix(video): PayScene restore top gradient bar on PaymentPanel (D31) Removed overly-aggressive `display: none !important` rule on `[data-testid="gradient-bar"]` that was hiding the violet→emerald top stripe on the payment panel. Replaced with: - `height: 12px !important` on the gradient bar (h-1 = 4px production is invisible at video resolution; 12px is visible without being disproportionate) - `animation: none !important` on `motion-safe:animate-pulse` to prevent CSS flicker at video FPS (gradient bar uses this class when pending) Both portrait (9x16) and landscape (16x9) affected via shared panelBorderStrip. * fix(video): PayScene kill text pulse animation + larger spinner (D32) Two fixes for connecting/sending button state in Remotion video: 1. `animate-breathing` override: SmartPayButtonView applies `motion-safe:animate-breathing` to the text label span during in-progress states. CSS animations run at arbitrary speed in Remotion (not frame-locked), causing scale-pulse flicker. Killed with `animation: none !important`. 2. Spinner size bump: Loader2Icon uses `size={18}` SVG prop (px attribute, not Tailwind class). Added `svg[width="18"]` cascade entry mapping to 48px — consistent with w-6/h-6 (48px) territory and visually proportional to the scaled-up button text. * fix(video): ShareScene tab swap layout stability (D33) Pre-mount QR tab one frame before swap (COPY_CLICK_FRAME-1) so QR content is in the DOM at the exact swap frame. Switch Link tab to position:absolute based on showQR flag (not linkTabOpacity float) so the container has a stable height holder (QR, position:relative) at every frame — eliminates the one-frame collapse that caused the stretch flicker on portrait and landscape. * fix(video): ShareScene landscape paper no-blur + top fit (D36+D37) D36: clamp PaperBackdrop top to Math.max(16, centered) — at 16:9 the paper (1123px tall at 0.92 scale) is taller than viewport height, giving negative top and overflowing above screen edge. D37: pass dimOpacity=1 blurPx=0 to landscape PaperBackdrop — landscape layout uses paper as persistent side-by-side context, not a backgrounded element, so blur/dim must never be applied. * fix(video): PayScene D34+D35+D36+D37+D38 round-9j fixes D34: emerald gradient bar override for data-status="paid" in panelBorderStrip D35: WalletPill connected only after PHASE_SWITCHING (170) not PHASE_CONNECTING (90) D36: landscape paper scale clamped by height (92% availableH) to prevent top overflow D37: landscape paper no blur/dim filter (removed opacity/filter from left column div) D38: PANEL_MAX_WIDTH 640→880 for proportional right column width * fix(video): CreateScene landscape paper height fit + scroll budget (D36) Paper: switch PaperBackdrop to height-driven sizing in landscape column mode (availableHeight * 0.92 → derive width from A4 ratio) to prevent top/bottom overflow on 16:9 (794×1123 paper at width-driven scale exceeded 1080px height). Scroll: add SCROLL_FRAMES_LANDSCAPE / SCROLL_OFFSETS_LANDSCAPE with endpoint -1160 (calibrated via stills) so Generate button is visible at BUTTON_VISIBLE=280. Portrait SCROLL_FRAMES/SCROLL_OFFSETS unchanged — 9:16 unaffected. * style(video): Caption visibility accent (D45) Raise border opacity 0.45→0.75, weight 1px→1.5px, glow 0.25→0.45, bg alpha 0.85→0.88, fontWeight 600→700. Add leading dot (12px filled circle with glow) matching HintBadge chip signature. Double boxShadow for stronger halo. Applies to all scenes using Caption. * style(video): ThesisOutro voidpay.xyz non-glow color (D46) Replace <RemotionAuroraText> wrapper on wordmark with plain violet-400 spans (#a78bfa). Both "voidpay" and ".xyz" use same color at fw700, "voidpay" gets text-decoration underline. Calm, brand-aligned link without animated aurora glow on final screen. * fix(video): ShareScene paper canonical sizing landscape (D39) Replace atlas-T Math.max(16, topCentered) clamp in PaperBackdrop with Kai-locked canonical formula: PAPER_VPAD=48, scaleByH=availH/BASE_HEIGHT, scaleByW=colW*0.85/BASE_WIDTH, scale=Math.min(scaleByW,scaleByH), top=PAPER_VPAD+(availH-BASE_HEIGHT*scale)/2. Guarantees ≥48px top/bottom margin and true centering in landscape column with no Math.max clamps. * fix(video): PayScene paper canonical sizing landscape (D39) Apply Kai-locked formula (PAPER_VPAD=48, availH excludes CHROME_HEIGHT, Math.min scale, centered with padding) to landscape branch, replacing the ad-hoc D36 formula. Column container heights kept as colH=height-CHROME_HEIGHT. * fix(video): PayScene WalletPill truly post-connection-complete (D42) Add PHASE_CONNECTED = PHASE_SENDING (frame 240) — the point after both connecting (90) and switching (170) animations complete and tx send begins. Apply to both portrait and landscape branches, replacing PHASE_CONNECTING (portrait) and PHASE_SWITCHING (landscape) which fired too early. * feat(video): extend Caption v2 API with kinetic typography mode Add position "center"|number, weight 700|500, emphasizedWord, and springConfig "smooth"|"overshoot" props per round-9l-spec §5/§6-A1. New kinetic mode activates only when new props are used — existing callers (pill chip UI) are fully backward-compatible. Animation helpers extracted to Caption.helpers.ts: - computeEntry: spring (700/overshoot) or bezier (500) - computeExit: universal 5fr opacity fade, no translateY - computeWordPopScale: scale 1→1.06→1 (700) or 1→1.04→1 (500) - computeWordPopColorOpacity: white→violet over 4fr, holds 90%, 6fr out - resolveYPercent: "top"=10% "bottom"=87% "center"=50% number=passthrough * feat(video): add S1 Create caption arrays per round-9l spec - New file: src/video/src/scenes/captions/create-captions.ts CaptionEntry type + CREATE_CAPTIONS_VERTICAL (4 entries, 9:16) and CREATE_CAPTIONS_LANDSCAPE (4 entries, 16:9) per §3/§4/§6-A3. - CreateScene.tsx: replace single "No signup." Caption with aspect-aware captions loop using useAspect() + captions array. Both portrait and landscape paths updated. HintBadges η7/η6/η2 (startAt 65/115/220) untouched. * feat(video): add Pay scene caption arrays + drop hint η (A5) - Create pay-captions.ts with PAY_CAPTIONS_VERTICAL (7) and PAY_CAPTIONS_LANDSCAPE (6) - Magic Dust hero caption (S-local 220-340) uses springConfig overshoot, position 50% center - Emerald variant activates from S-local 425 onward in both orientations - Replace hardcoded Captions in PayScene with array-driven map (portrait + landscape) - Remove HintBadge "unique micro-amount ← payment ID" from both branches (narrative duplication) * feat(video): add S2 Share caption arrays and drop η5 HintBadge Implements round-9l spec §3+§4 for ShareScene: - create share-captions.ts with SHARE_CAPTIONS_VERTICAL (4 entries, 9:16) and SHARE_CAPTIONS_LANDSCAPE (4 entries, 16:9) arrays - replace single legacy "URL = invoice." Caption with captions.map loop in both portrait and landscape branches - remove η5 HintBadge ("invoice data → in the hash") from both branches; narrative covered by "Hash never leaves the browser." caption - remove unused HintBadge import * feat(video): add 6 hook-variant compositions + wire hookVariant prop Round 9l (row A7): split VoidPayDemo into 6 compositions (3 hook variants × 2 aspect ratios). Old IDs VoidPayDemo-9x16 and VoidPayDemo-16x9 kept as v1 aliases for backward-compat. - VoidPayDemo.tsx: add hookVariant prop (default "v1"), pass to ThesisHookScene - Root.tsx: 6 named compositions (-v1/-v2/-v3 × 9x16/16x9) + 2 legacy aliases - AC2: no <Audio> components in composition tree (silent video confirmed) * feat(video): apply Path C pill backdrop to kinetic Caption mode Kinetic mode now renders a dark pill wrapper (rgba(20,20,27,0.85), blur(10px), violet/emerald border+glow, border-radius 28px) with an 18×18 leading dot and spec-canonical padding/gap. TranslateY entry animation applies to the outer pill so the whole pill slides in/out. Word-pop emphasized-word transition (white→#a78bfa scale 1→1.18→1) is preserved. Compact path activates when fontSize<=80 (22px 44px / 18px gap). -webkit-backdropFilter added for Safari. Legacy pill mode: unchanged. * fix(video): round-9m PayScene — re-sequence S2→S3 timing, MD halo, captions, hint - Blocker #1: re-sequence stepAt() — idle:disconnected 0-200, idle:connected 200-220, sending 220-310, confirming 310-440, success 440+ (was: connecting/switching intermediate steps) - Blocker #2: paperPaid gate already correct (step==='success'); confirmed no regression - Blocker #3: violet halo opacity now keyed to [220,240,310,330] per brief spec - UI dim wrap: BrowserChrome+panel wrapped in opacity div [200,212,308,320]→[1.0,0.4,0.4,1.0] - Caption ε3: "Open link. Pay." inline at S3-local 15→80 (portrait pos=920, landscape pos=80%) - Hint η4: HintBadge "unique micro-amount ← payment ID" at S3-local 230→310 - Toast timings realigned: wallet-connected→200, network-switched→210, confirming→310, success→440 - Import: added HintBadge from ../components/HintBadge * refactor(video): round-9p font shrink, drop ε3 inline, hint size down Task A — caption font one register down (vertical only, landscape untouched): - hero 86→72, sub 60→50 in create/share/pay/thesis caption data - ThesisHookScene + ThesisOutroScene captionFontSize override 60→50 Task B — drop ε3 inline "Open link. Pay." from PayScene (landscape + portrait); PAY_CAPTIONS_VERTICAL[0] already renders "Payer opens the link." in the same window, so removing the duplicate eliminates the f15-70 overlap. Task C — HintBadge size one register down: - portrait 32→28 (PayScene η4, ShareScene η5, CreateScene 3×) - landscape 24→22 (CreateScene 3×, PayScene η4) * feat(video): round-9q caption and hint-badge overhaul S0 (ThesisHookScene): hook window shortened 5→45; second caption "Raw addresses look unprofessional." added at frames 50-85 (aspect-aware). S1 (CreateScene): new caption arc — Create an invoice → No signup → No account. No KYC. → Get a link. Both portrait and landscape arrays rebuilt per round-9q spec. Inline ε1 "No signup." Caption removed. Dead "Fill a form." filter removed. S1/S2/S3: all 8 HintBadge JSX instances removed (3 portrait + 3 landscape in CreateScene, 1 in ShareScene, 2 in PayScene). Three HintBadge imports removed. Component file kept. * chore(video): commit Round 9n leftover before develop merge Preserves uncommitted prior-session work as stable point ahead of develop sync (216 commits behind): - invoice-paper: magicDustEmphasis prop (5 files) — violet-highlighted magic-dust digits in merged total per Round 9n Kai-sweep - src/video/src/Root.tsx: hookVariant schema (v1/v2/v3) for A/B hook copy - src/video/src/components/Caption.tsx: Path-C pill kinetic-mode alignment - src/video/src/hooks/useAspect.ts: aspect-aware sizing helper (untracked) All paths match handoff 2026-05-15-video-captions-9q.md "Files touched in prior rounds (stable)". Type-check + lint were green at end of 9q. * feat(video): round-9r PayScene phase reshuffle + toast/caption polish PayScene: split Connect → Switch → Pay into three distinct presses; expand stepAt to cover connecting/wrong-network/switching/ready substates; shift confirming/success back by 60fr for longer paid-alone window. RemotionFakeToast: rightAlign prop for landscape to avoid caption collision; drop z-index from 9999 → 90 so captions (z=100) sit above. ShareScene: gradient bar 4px → 8px (matches production ShareModal). Captions: nudge landscape Magic-Dust + hook + outro captions to position=80 to clear paper/panel in 16:9. Pre-refactor snapshot — next commits split scenes into sub-directories. * feat(video): unified PaperBackdrop component (D39 canonical sizing) Adds src/video/src/components/PaperBackdrop.tsx — shared component for use in Phase 2 refactor of CreateScene/PayScene/ShareScene local copies. Implements Kai-locked D39 formula: PAD=48, scale=min(scaleByW,scaleByH), top centered within available height. No internal animation; scenes own entrance/dim envelopes. * refactor(video): split PayScene into scene/ sub-modules, adopt shared PaperBackdrop Extracts constants, stepAt+pressScale, panel cascade/border style components, MagicDustHalo, PaymentPanelContent, and landscape/portrait branches into scenes/pay/ sub-directory. Local PaperBackdrop replaced by shared components/PaperBackdrop. Landscape paper unchanged (already D39 canonical). Portrait paper sizing shifts from 0.92×width to 0.85×width with PAD=48 — drift fix approved by Kai (2026-05-16). CHROME_HEIGHT now passed via containerHeight + parent top offset, replacing the legacy offsetTop prop. * refactor(video): split ShareScene into scene/ sub-modules, adopt shared PaperBackdrop Extracts constants, SummaryCascade style components, and landscape/portrait branches into scenes/share/ sub-directory. Local PaperBackdrop replaced by shared components/PaperBackdrop. Visual identical — ShareScene was already on D39 canonical formula (the reference for Kai's drift fix). Modal shell duplication between branches preserved; consolidation deferred to a future refactor. * refactor(video): split CreateScene into scene/ sub-modules, adopt shared PaperBackdrop Extracts constants, typewrite helper, PortraitCascade style block, and landscape/portrait branches into scenes/create/ sub-directory. Local PaperBackdrop replaced by shared components/PaperBackdrop wrapped in CreateScenePaperEnvelope (preserves entrance animation + scale ramp). Visual: landscape unchanged (already D39 canonical). Portrait paper sizing shifts from 0.92×width to 0.85×width with PAD=48 — drift fix approved by Kai (2026-05-16). * refactor(video): PayScene drift cleanup — adopt shared PaperBackdrop in landscape, dedupe constants Replaces inline InvoicePaper rendering in PaySceneLandscape with shared components/PaperBackdrop (math is identical — was accidental duplication). Replaces literal DEMO_TX_HASH and hardcoded confirmations counts with imports from scenes/pay/constants. * feat(ui): add readOnly prop to Input for display-only contexts * refactor(invoice-form): split MetadataSection into Container + View * refactor(invoice-form): split PartySection into Container + View * refactor(payment): split IdleSubState — production union narrow, AnimatedIdleSubState for Views IdleSubState is now the 3-element production union (disconnected|wrong-network|ready). AnimatedIdleSubState is the 5-element superset adding connecting|switching for Remotion scenes. SmartPayButtonView.tsx props/helpers updated to AnimatedIdleSubState. parseDevOverride return type updated accordingly. Container (SmartPayButton.tsx) stays IdleSubState via usePaymentFlow; widens to AnimatedIdleSubState when passed to View — no cast needed. * refactor(invoice-form): split LineItemsSection into Container + View * refactor(invoice-form): split PaymentSection into Container + View * refactor(invoice-form): split LinkOptionsSection into Container + View * refactor(invoice-form): compose InvoiceFormView from real SectionViews - Delete inline MetadataSectionView, PartySectionView, LineItemsSectionView, LineItemsViewRow, PaymentSectionView, MagicDustView, focusRing() helper - Compose from ./sections/*SectionView components - Replace ReadonlyInput with <Input readOnly /> (ReadonlyInput.tsx emptied) - InvoiceFormView reduced from 382 LOC to ~115 LOC * refactor(payment): lift IN_PROGRESS_STEPS to model/types Moved IN_PROGRESS_STEPS Set from SmartPayButtonView.tsx inline const into model/types.ts as the single source of truth. SmartPayButtonView imports it from model; local duplicate removed. * refactor(invoice-form): move View exports to /video-internals subpath - sections/index.ts: export all *SectionView components alongside Containers - index.ts: remove all View exports (InvoiceFormView, GenerateButton*View, *SectionView) - video-internals.ts: new subpath barrel for Remotion — exports InvoiceFormView + all SectionViews + GenerateButtonView FOLLOWUP: update src/video imports to use @/widgets/invoice-form/video-internals * fix(invoice-form): exactOptionalPropertyTypes fixes in InvoiceFormView and LineItemsSectionView * refactor(payment): move SmartPayButtonView to /video-internals subpath - Create src/features/payment/video-internals.ts barrel exporting SmartPayButtonView, SmartPayButtonViewProps, AnimatedIdleSubState - Remove SmartPayButtonView/SmartPayButtonViewProps from main index.ts barrel - SmartPayButtonView helpers (getButtonLabel, getProgress, getAriaLabel) made private — no longer exported; View is the single source of truth - getStepCount returns number directly (offset field was never read) - SmartPayButton: drop getAriaLabel import and ariaLabel prop pass-through; View self-computes via isHydrating+idleSubState - SmartPayButton: use IN_PROGRESS_STEPS.has() instead of inline array check * fix(ui): re-tokenize Tabs to VoidPay zinc/violet palette Replaced stock shadcn tokens (bg-muted, text-muted-foreground, ring-ring, ring-offset-background, bg-background, text-foreground) which are undefined in VoidPay's Tailwind config with explicit zinc/violet classes matching the removed TabSwitcher.tsx palette: - TabsList: border-zinc-800 bg-zinc-950/50 text-zinc-500 - TabsTrigger active: bg-zinc-800 text-zinc-100 - Focus ring: violet-500 on zinc-950 offset Also converted double quotes to single quotes (project convention). * fix(share-modal): restore tab icons, narrow tab value coercion - Restore LinkIcon + QrCodeIcon in TabsTrigger children (UX regression from TabSwitcher→Tabs migration — icons were present in original TabSwitcher) - Replace (v as ShareTab) cast with toShareTab() narrow guard ('qr' | fallback 'link') — eliminates unchecked type assertion * fix(video): update imports to /video-internals subpaths after barrel migration * refactor(invoice): move…
ignromanov
added a commit
that referenced
this pull request
May 19, 2026
…#240) * docs: update privacy policy with Umami analytics details Add dedicated "Product Analytics" section, add Umami to Third-Party Services, fix misleading "Analytics or telemetry" item in "What We Don't Collect" section. * fix(demo): correct demo invoice data and native token template loading - Fix txHash #1 missing 2 hex chars (62→64 hex digits) - Remove redundant "(40 hours)" from description where qty=40 - Change Invoice #2 discount from 8% to 5% so tax/discount don't cancel out - Fix native token (ETH, POL) not recognized when loading invoice as template: spread merge didn't clear default tokenAddress when decoded data omits the key * docs: add community files, security policy, README redesign - LICENSE (MIT) - SECURITY.md + public/.well-known/security.txt (RFC 9116) - CONTRIBUTING.md, CODE_OF_CONDUCT.md (Contributor Covenant v2.1) - README.md full redesign: badges, How It Works, features, quick start - .github/FUNDING.yml (GitHub Sponsors + Giveth) - .github/dependabot.yml (weekly npm, monthly GHA) - .github/pull_request_template.md - .github/ISSUE_TEMPLATE/feature_request.md * fix(docs): simplify PR template to match existing style Summary + Test plan (lowercase), no generic checklist — CI handles validation. * fix(docs): PR template with structured summary and specific test plan Matches PR #45 style: subsections for larger PRs, concrete test checkboxes. * ci: add Dependabot auto-merge for patch and minor updates Auto-approve and squash-merge Dependabot PRs for patch/minor versions after CI passes. Major version updates require manual review. * build(deps-dev): bump tailwindcss from 4.1.18 to 4.2.2 (#70) Bumps [tailwindcss](https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/tailwindcss) from 4.1.18 to 4.2.2. - [Release notes](https://github.com/tailwindlabs/tailwindcss/releases) - [Changelog](https://github.com/tailwindlabs/tailwindcss/blob/main/CHANGELOG.md) - [Commits](https://github.com/tailwindlabs/tailwindcss/commits/v4.2.2/packages/tailwindcss) --- updated-dependencies: - dependency-name: tailwindcss dependency-version: 4.2.2 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump tailwind-merge from 3.4.0 to 3.5.0 (#62) Bumps [tailwind-merge](https://github.com/dcastil/tailwind-merge) from 3.4.0 to 3.5.0. - [Release notes](https://github.com/dcastil/tailwind-merge/releases) - [Commits](https://github.com/dcastil/tailwind-merge/compare/v3.4.0...v3.5.0) --- updated-dependencies: - dependency-name: tailwind-merge dependency-version: 3.5.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump zustand from 5.0.9 to 5.0.12 (#68) Bumps [zustand](https://github.com/pmndrs/zustand) from 5.0.9 to 5.0.12. - [Release notes](https://github.com/pmndrs/zustand/releases) - [Commits](https://github.com/pmndrs/zustand/compare/v5.0.9...v5.0.12) --- updated-dependencies: - dependency-name: zustand dependency-version: 5.0.12 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps-dev): bump lint-staged from 16.2.7 to 16.4.0 (#61) Bumps [lint-staged](https://github.com/lint-staged/lint-staged) from 16.2.7 to 16.4.0. - [Release notes](https://github.com/lint-staged/lint-staged/releases) - [Changelog](https://github.com/lint-staged/lint-staged/blob/main/CHANGELOG.md) - [Commits](https://github.com/lint-staged/lint-staged/compare/v16.2.7...v16.4.0) --- updated-dependencies: - dependency-name: lint-staged dependency-version: 16.4.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump viem from 2.43.4 to 2.47.6 (#63) Bumps [viem](https://github.com/wevm/viem) from 2.43.4 to 2.47.6. - [Release notes](https://github.com/wevm/viem/releases) - [Commits](https://github.com/wevm/viem/compare/viem@2.43.4...viem@2.47.6) --- updated-dependencies: - dependency-name: viem dependency-version: 2.47.6 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps-dev): bump @next/eslint-plugin-next from 16.1.1 to 16.2.1 (#69) Bumps [@next/eslint-plugin-next](https://github.com/vercel/next.js/tree/HEAD/packages/eslint-plugin-next) from 16.1.1 to 16.2.1. - [Release notes](https://github.com/vercel/next.js/releases) - [Changelog](https://github.com/vercel/next.js/blob/canary/release.js) - [Commits](https://github.com/vercel/next.js/commits/v16.2.1/packages/eslint-plugin-next) --- updated-dependencies: - dependency-name: "@next/eslint-plugin-next" dependency-version: 16.2.1 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump zod from 4.3.4 to 4.3.6 (#66) Bumps [zod](https://github.com/colinhacks/zod) from 4.3.4 to 4.3.6. - [Release notes](https://github.com/colinhacks/zod/releases) - [Commits](https://github.com/colinhacks/zod/compare/v4.3.4...v4.3.6) --- updated-dependencies: - dependency-name: zod dependency-version: 4.3.6 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * fix(github): issue templates frontmatter, dependabot auto-merge workflow - Add name/about/title/assignees to issue templates so GitHub recognizes them - Create config.yml disabling blank issues with security advisory link - Replace dependabot-auto-merge.yml with simplified dependabot-automerge.yml * build(deps-dev): bump lucide-static from 0.577.0 to 1.7.0 (#67) Bumps [lucide-static](https://github.com/lucide-icons/lucide) from 0.577.0 to 1.7.0. - [Release notes](https://github.com/lucide-icons/lucide/releases) - [Commits](https://github.com/lucide-icons/lucide/compare/0.577.0...1.7.0) --- updated-dependencies: - dependency-name: lucide-static dependency-version: 1.7.0 dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps-dev): bump @types/node from 22.19.3 to 25.5.0 (#65) Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 22.19.3 to 25.5.0. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node) --- updated-dependencies: - dependency-name: "@types/node" dependency-version: 25.5.0 dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump actions/upload-artifact from 4 to 7 (#60) Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4 to 7. - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/v4...v7) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-version: '7' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump pnpm/action-setup from 4 to 5 (#59) Bumps [pnpm/action-setup](https://github.com/pnpm/action-setup) from 4 to 5. - [Release notes](https://github.com/pnpm/action-setup/releases) - [Commits](https://github.com/pnpm/action-setup/compare/v4...v5) --- updated-dependencies: - dependency-name: pnpm/action-setup dependency-version: '5' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump actions/checkout from 4 to 6 (#58) Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 6. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v4...v6) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump actions/cache from 4 to 5 (#57) Bumps [actions/cache](https://github.com/actions/cache) from 4 to 5. - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](https://github.com/actions/cache/compare/v4...v5) --- updated-dependencies: - dependency-name: actions/cache dependency-version: '5' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump actions/setup-node from 4 to 6 (#56) Bumps [actions/setup-node](https://github.com/actions/setup-node) from 4 to 6. - [Release notes](https://github.com/actions/setup-node/releases) - [Commits](https://github.com/actions/setup-node/compare/v4...v6) --- updated-dependencies: - dependency-name: actions/setup-node dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump picomatch from 2.3.1 to 2.3.2 (#55) Bumps [picomatch](https://github.com/micromatch/picomatch) from 2.3.1 to 2.3.2. - [Release notes](https://github.com/micromatch/picomatch/releases) - [Changelog](https://github.com/micromatch/picomatch/blob/master/CHANGELOG.md) - [Commits](https://github.com/micromatch/picomatch/compare/2.3.1...2.3.2) --- updated-dependencies: - dependency-name: picomatch dependency-version: 2.3.2 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps-dev): bump vitest and @vitest/coverage-istanbul (#64) Bumps [vitest](https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest) and [@vitest/coverage-istanbul](https://github.com/vitest-dev/vitest/tree/HEAD/packages/coverage-istanbul). These dependencies needed to be updated together. Updates `vitest` from 4.0.16 to 4.1.2 - [Release notes](https://github.com/vitest-dev/vitest/releases) - [Commits](https://github.com/vitest-dev/vitest/commits/v4.1.2/packages/vitest) Updates `@vitest/coverage-istanbul` from 4.0.16 to 4.1.2 - [Release notes](https://github.com/vitest-dev/vitest/releases) - [Commits](https://github.com/vitest-dev/vitest/commits/v4.1.2/packages/coverage-istanbul) --- updated-dependencies: - dependency-name: vitest dependency-version: 4.1.2 dependency-type: direct:development update-type: version-update:semver-minor - dependency-name: "@vitest/coverage-istanbul" dependency-version: 4.1.2 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump the npm_and_yarn group across 1 directory with 11 updates (#71) Bumps the npm_and_yarn group with 11 updates in the / directory: | Package | From | To | | --- | --- | --- | | [next](https://github.com/vercel/next.js) | `15.5.9` | `15.5.14` | | [happy-dom](https://github.com/capricorn86/happy-dom) | `20.0.11` | `20.8.9` | | [ajv](https://github.com/ajv-validator/ajv) | `6.12.6` | `6.14.0` | | [axios](https://github.com/axios/axios) | `1.13.2` | `1.14.0` | | [brace-expansion](https://github.com/juliangruber/brace-expansion) | `1.1.12` | `1.1.13` | | [flatted](https://github.com/WebReflection/flatted) | `3.3.3` | `3.4.2` | | [h3](https://github.com/h3js/h3) | `1.15.4` | `1.15.10` | | [hono](https://github.com/honojs/hono) | `4.11.3` | `4.12.9` | | [minimatch](https://github.com/isaacs/minimatch) | `3.1.2` | `3.1.5` | | [rollup](https://github.com/rollup/rollup) | `4.54.0` | `4.60.1` | | [socket.io-parser](https://github.com/socketio/socket.io) | `4.2.5` | `4.2.6` | Updates `next` from 15.5.9 to 15.5.14 - [Release notes](https://github.com/vercel/next.js/releases) - [Changelog](https://github.com/vercel/next.js/blob/canary/release.js) - [Commits](https://github.com/vercel/next.js/compare/v15.5.9...v15.5.14) Updates `happy-dom` from 20.0.11 to 20.8.9 - [Release notes](https://github.com/capricorn86/happy-dom/releases) - [Commits](https://github.com/capricorn86/happy-dom/compare/v20.0.11...v20.8.9) Updates `ajv` from 6.12.6 to 6.14.0 - [Release notes](https://github.com/ajv-validator/ajv/releases) - [Commits](https://github.com/ajv-validator/ajv/compare/v6.12.6...v6.14.0) Updates `axios` from 1.13.2 to 1.14.0 - [Release notes](https://github.com/axios/axios/releases) - [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md) - [Commits](https://github.com/axios/axios/compare/v1.13.2...v1.14.0) Updates `brace-expansion` from 1.1.12 to 1.1.13 - [Release notes](https://github.com/juliangruber/brace-expansion/releases) - [Commits](https://github.com/juliangruber/brace-expansion/compare/v1.1.12...v1.1.13) Updates `flatted` from 3.3.3 to 3.4.2 - [Commits](https://github.com/WebReflection/flatted/compare/v3.3.3...v3.4.2) Updates `h3` from 1.15.4 to 1.15.10 - [Release notes](https://github.com/h3js/h3/releases) - [Changelog](https://github.com/h3js/h3/blob/v1.15.10/CHANGELOG.md) - [Commits](https://github.com/h3js/h3/compare/v1.15.4...v1.15.10) Updates `hono` from 4.11.3 to 4.12.9 - [Release notes](https://github.com/honojs/hono/releases) - [Commits](https://github.com/honojs/hono/compare/v4.11.3...v4.12.9) Updates `minimatch` from 3.1.2 to 3.1.5 - [Changelog](https://github.com/isaacs/minimatch/blob/main/changelog.md) - [Commits](https://github.com/isaacs/minimatch/compare/v3.1.2...v3.1.5) Updates `rollup` from 4.54.0 to 4.60.1 - [Release notes](https://github.com/rollup/rollup/releases) - [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md) - [Commits](https://github.com/rollup/rollup/compare/v4.54.0...v4.60.1) Updates `socket.io-parser` from 4.2.5 to 4.2.6 - [Release notes](https://github.com/socketio/socket.io/releases) - [Changelog](https://github.com/socketio/socket.io/blob/main/CHANGELOG.md) - [Commits](https://github.com/socketio/socket.io/compare/socket.io-parser@4.2.5...socket.io-parser@4.2.6) --- updated-dependencies: - dependency-name: next dependency-version: 15.5.14 dependency-type: direct:production dependency-group: npm_and_yarn - dependency-name: happy-dom dependency-version: 20.8.9 dependency-type: direct:development dependency-group: npm_and_yarn - dependency-name: ajv dependency-version: 6.14.0 dependency-type: indirect dependency-group: npm_and_yarn - dependency-name: axios dependency-version: 1.14.0 dependency-type: indirect dependency-group: npm_and_yarn - dependency-name: brace-expansion dependency-version: 1.1.13 dependency-type: indirect dependency-group: npm_and_yarn - dependency-name: flatted dependency-version: 3.4.2 dependency-type: indirect dependency-group: npm_and_yarn - dependency-name: h3 dependency-version: 1.15.10 dependency-type: indirect dependency-group: npm_and_yarn - dependency-name: hono dependency-version: 4.12.9 dependency-type: indirect dependency-group: npm_and_yarn - dependency-name: minimatch dependency-version: 3.1.5 dependency-type: indirect dependency-group: npm_and_yarn - dependency-name: rollup dependency-version: 4.60.1 dependency-type: indirect dependency-group: npm_and_yarn - dependency-name: socket.io-parser dependency-version: 4.2.6 dependency-type: indirect dependency-group: npm_and_yarn ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump yaml from 2.8.2 to 2.8.3 (#53) Bumps [yaml](https://github.com/eemeli/yaml) from 2.8.2 to 2.8.3. - [Release notes](https://github.com/eemeli/yaml/releases) - [Commits](https://github.com/eemeli/yaml/compare/v2.8.2...v2.8.3) --- updated-dependencies: - dependency-name: yaml dependency-version: 2.8.3 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump @xmldom/xmldom (#72) Bumps the npm_and_yarn group with 1 update in the / directory: [@xmldom/xmldom](https://github.com/xmldom/xmldom). Updates `@xmldom/xmldom` from 0.8.11 to 0.8.12 - [Release notes](https://github.com/xmldom/xmldom/releases) - [Changelog](https://github.com/xmldom/xmldom/blob/master/CHANGELOG.md) - [Commits](https://github.com/xmldom/xmldom/compare/0.8.11...0.8.12) --- updated-dependencies: - dependency-name: "@xmldom/xmldom" dependency-version: 0.8.12 dependency-type: indirect dependency-group: npm_and_yarn ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * docs: add Drips FUNDING.json + fix Giveth URL in FUNDING.yml - FUNDING.json: Drips Network project claim (treasury wallet) - FUNDING.yml: correct Giveth project URL slug * Add newline at end of FUNDING.json Fix formatting by adding a newline at the end of the file. * docs: add OP Atlas projectId to FUNDING.json * docs: add Optimism network to Drips FUNDING.json * docs: add Buy Me a Coffee to FUNDING.yml * build(deps): bump lodash in the npm_and_yarn group across 1 directory (#78) Bumps the npm_and_yarn group with 1 update in the / directory: [lodash](https://github.com/lodash/lodash). Updates `lodash` from 4.17.21 to 4.18.1 - [Release notes](https://github.com/lodash/lodash/releases) - [Commits](https://github.com/lodash/lodash/compare/4.17.21...4.18.1) --- updated-dependencies: - dependency-name: lodash dependency-version: 4.18.1 dependency-type: indirect dependency-group: npm_and_yarn ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump defu in the npm_and_yarn group across 1 directory (#80) Bumps the npm_and_yarn group with 1 update in the / directory: [defu](https://github.com/unjs/defu). Updates `defu` from 6.1.4 to 6.1.6 - [Release notes](https://github.com/unjs/defu/releases) - [Changelog](https://github.com/unjs/defu/blob/main/CHANGELOG.md) - [Commits](https://github.com/unjs/defu/compare/v6.1.4...v6.1.6) --- updated-dependencies: - dependency-name: defu dependency-version: 6.1.6 dependency-type: indirect dependency-group: npm_and_yarn ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * fix: remove robots.txt (static export doesn't serve it) * feat: add 512x512 app icon for PWA and social sharing * feat: add TalentApp domain verification meta tag * build(deps): bump @tanstack/react-query from 5.90.16 to 5.96.2 (#82) Bumps [@tanstack/react-query](https://github.com/TanStack/query/tree/HEAD/packages/react-query) from 5.90.16 to 5.96.2. - [Release notes](https://github.com/TanStack/query/releases) - [Changelog](https://github.com/TanStack/query/blob/main/packages/react-query/CHANGELOG.md) - [Commits](https://github.com/TanStack/query/commits/@tanstack/react-query@5.96.2/packages/react-query) --- updated-dependencies: - dependency-name: "@tanstack/react-query" dependency-version: 5.96.2 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps-dev): bump @next/eslint-plugin-next from 16.2.1 to 16.2.2 (#84) Bumps [@next/eslint-plugin-next](https://github.com/vercel/next.js/tree/HEAD/packages/eslint-plugin-next) from 16.2.1 to 16.2.2. - [Release notes](https://github.com/vercel/next.js/releases) - [Changelog](https://github.com/vercel/next.js/blob/canary/release.js) - [Commits](https://github.com/vercel/next.js/commits/v16.2.2/packages/eslint-plugin-next) --- updated-dependencies: - dependency-name: "@next/eslint-plugin-next" dependency-version: 16.2.2 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump framer-motion from 12.23.26 to 12.38.0 (#87) Bumps [framer-motion](https://github.com/motiondivision/motion) from 12.23.26 to 12.38.0. - [Changelog](https://github.com/motiondivision/motion/blob/main/CHANGELOG.md) - [Commits](https://github.com/motiondivision/motion/compare/v12.23.26...v12.38.0) --- updated-dependencies: - dependency-name: framer-motion dependency-version: 12.38.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps-dev): bump @vitejs/plugin-react from 5.1.2 to 5.2.0 (#88) Bumps [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/tree/HEAD/packages/plugin-react) from 5.1.2 to 5.2.0. - [Release notes](https://github.com/vitejs/vite-plugin-react/releases) - [Changelog](https://github.com/vitejs/vite-plugin-react/blob/plugin-react@5.2.0/packages/plugin-react/CHANGELOG.md) - [Commits](https://github.com/vitejs/vite-plugin-react/commits/plugin-react@5.2.0/packages/plugin-react) --- updated-dependencies: - dependency-name: "@vitejs/plugin-react" dependency-version: 5.2.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps-dev): bump postcss from 8.5.6 to 8.5.8 (#89) Bumps [postcss](https://github.com/postcss/postcss) from 8.5.6 to 8.5.8. - [Release notes](https://github.com/postcss/postcss/releases) - [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md) - [Commits](https://github.com/postcss/postcss/compare/8.5.6...8.5.8) --- updated-dependencies: - dependency-name: postcss dependency-version: 8.5.8 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps-dev): bump typescript-eslint from 8.51.0 to 8.58.0 (#92) Bumps [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint) from 8.51.0 to 8.58.0. - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-eslint/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.58.0/packages/typescript-eslint) --- updated-dependencies: - dependency-name: typescript-eslint dependency-version: 8.58.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps-dev): bump @testing-library/react from 16.3.1 to 16.3.2 (#93) Bumps [@testing-library/react](https://github.com/testing-library/react-testing-library) from 16.3.1 to 16.3.2. - [Release notes](https://github.com/testing-library/react-testing-library/releases) - [Changelog](https://github.com/testing-library/react-testing-library/blob/main/CHANGELOG.md) - [Commits](https://github.com/testing-library/react-testing-library/compare/v16.3.1...v16.3.2) --- updated-dependencies: - dependency-name: "@testing-library/react" dependency-version: 16.3.2 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump @web3icons/react from 4.1.14 to 4.1.17 (#94) Bumps [@web3icons/react](https://github.com/0xa3k5/web3icons/tree/HEAD/packages/react) from 4.1.14 to 4.1.17. - [Release notes](https://github.com/0xa3k5/web3icons/releases) - [Changelog](https://github.com/0xa3k5/web3icons/blob/main/packages/react/CHANGELOG.md) - [Commits](https://github.com/0xa3k5/web3icons/commits/@web3icons/react@4.1.17/packages/react) --- updated-dependencies: - dependency-name: "@web3icons/react" dependency-version: 4.1.17 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump @upstash/ratelimit from 2.0.7 to 2.0.8 (#91) Bumps [@upstash/ratelimit](https://github.com/upstash/ratelimit) from 2.0.7 to 2.0.8. - [Release notes](https://github.com/upstash/ratelimit/releases) - [Commits](https://github.com/upstash/ratelimit/compare/v2.0.7...v2.0.8) --- updated-dependencies: - dependency-name: "@upstash/ratelimit" dependency-version: 2.0.8 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps-dev): bump @eslint/eslintrc from 3.3.3 to 3.3.5 (#96) Bumps [@eslint/eslintrc](https://github.com/eslint/eslintrc) from 3.3.3 to 3.3.5. - [Release notes](https://github.com/eslint/eslintrc/releases) - [Changelog](https://github.com/eslint/eslintrc/blob/main/CHANGELOG.md) - [Commits](https://github.com/eslint/eslintrc/compare/eslintrc-v3.3.3...eslintrc-v3.3.5) --- updated-dependencies: - dependency-name: "@eslint/eslintrc" dependency-version: 3.3.5 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump pixi.js from 8.14.3 to 8.17.1 (#100) Bumps [pixi.js](https://github.com/pixijs/pixijs) from 8.14.3 to 8.17.1. - [Release notes](https://github.com/pixijs/pixijs/releases) - [Commits](https://github.com/pixijs/pixijs/compare/v8.14.3...v8.17.1) --- updated-dependencies: - dependency-name: pixi.js dependency-version: 8.17.1 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump geist from 1.5.1 to 1.7.0 (#98) Bumps [geist](https://github.com/vercel/geist-font/tree/HEAD/packages/next) from 1.5.1 to 1.7.0. - [Release notes](https://github.com/vercel/geist-font/releases) - [Changelog](https://github.com/vercel/geist-font/blob/main/packages/next/CHANGELOG.md) - [Commits](https://github.com/vercel/geist-font/commits/geist@1.7.0/packages/next) --- updated-dependencies: - dependency-name: geist dependency-version: 1.7.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps-dev): bump @types/node from 25.5.0 to 25.5.2 (#99) Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 25.5.0 to 25.5.2. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node) --- updated-dependencies: - dependency-name: "@types/node" dependency-version: 25.5.2 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump viem from 2.47.6 to 2.47.10 (#97) Bumps [viem](https://github.com/wevm/viem) from 2.47.6 to 2.47.10. - [Release notes](https://github.com/wevm/viem/releases) - [Commits](https://github.com/wevm/viem/compare/viem@2.47.6...viem@2.47.10) --- updated-dependencies: - dependency-name: viem dependency-version: 2.47.10 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps-dev): bump @eslint/js from 9.39.2 to 9.39.4 (#101) Bumps [@eslint/js](https://github.com/eslint/eslint/tree/HEAD/packages/js) from 9.39.2 to 9.39.4. - [Release notes](https://github.com/eslint/eslint/releases) - [Commits](https://github.com/eslint/eslint/commits/v9.39.4/packages/js) --- updated-dependencies: - dependency-name: "@eslint/js" dependency-version: 9.39.4 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps-dev): bump vite in the npm_and_yarn group across 1 directory (#102) Bumps the npm_and_yarn group with 1 update in the / directory: [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite). Updates `vite` from 7.3.0 to 7.3.2 - [Release notes](https://github.com/vitejs/vite/releases) - [Changelog](https://github.com/vitejs/vite/blob/v7.3.2/packages/vite/CHANGELOG.md) - [Commits](https://github.com/vitejs/vite/commits/v7.3.2/packages/vite) --- updated-dependencies: - dependency-name: vite dependency-version: 7.3.2 dependency-type: direct:development dependency-group: npm_and_yarn ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * refactor(history): redesign history page cards with payment panel style (#103) * feat(history): add StatusGradientBar component * feat(history): add NetworkBadge component with tests * refactor(history): redesign InvoiceStatusBadge with dot + glow * refactor(history): restyle InvoiceCardShell with zinc-900 + gradient bar * refactor(history): rewrite HistoryList with new card layout, network badge, subtotal * refactor(history): rewrite ReceivedInvoiceList with unified card design + Template button * refactor(history): update HistoryWorkspace colors gray→zinc * fix(history): remove unused type imports in ReceivedInvoiceList * refactor(history): extract shared InvoiceCard, remove duplicate card components Unified HistoryEntryCard and ReceivedInvoiceCard (~95% identical) into a single InvoiceCard with a nameLabel prop. Removed defeated memo(), pointless useMemo, dead source prop, and unnecessary JSX comments. Collapsed identical DecodedReceivedInvoice type into alias for DecodedHistoryEntry. * refactor(history): consolidate duplicated configs, merge list components - Merge HistoryList + ReceivedInvoiceList into unified InvoiceList with variant prop ('created'|'received') controlling route, name, empty text - Extract INVOICE_STATUS_CHIPS to entities/invoice for shared status colors consumed by InvoiceStatusBadge (features) and StatusChip (widgets) - Move network badge dark-mode colors to entities/network (NETWORK_BADGES_DARK) - Add formatDateMedium, formatDateCompact, isoToUnix to shared/lib/date-time - Remove deprecated DecodedReceivedInvoice type alias - Net -54 lines, 59/59 tests pass, tsc + lint clean * feat: add Base network (8453) + refactor network visual system (#79) * fix: remove robots.txt (static export doesn't serve it) * feat: add BaseIcon SVG component for Base network * feat: add Base (8453) and Base Sepolia (84532) to chain config * feat: add Base network metadata and codes * feat: add Base token registry (ETH, USDC, USDT) * feat: add Base provider slugs for Alchemy and Infura * feat: add Base confirmation config (OP Stack) * feat: add Base block estimation parameters * feat: add Base UI theming, badges, glows, and explorer * feat: add Base RPC URL env vars to schema * fix: add Base to theme configs, update chain count tests and snapshots * fix: add Base to NetworkIcon component (web3icons + fallback) * fix: update Base reference block from live explorer data * refactor: remove unused BaseIcon (NetworkIcon uses @web3icons/react) * fix: boost Base glow opacity (blue is subtle on dark background) * revert: restore original Base glow values * fix: resolve testnet glow/shadow/badge lookups via withTestnets helper Visual config Records (NETWORK_SHADOWS, NETWORK_GLOWS, NETWORK_GLOW_SHADOWS, NETWORK_GLOW_BORDERS, NETWORK_BADGES) were keyed by mainnet chain IDs only, causing missing glow on testnet invoices (e.g. Base Sepolia 84532). Added withTestnets() helper that auto-derives testnet entries from TESTNET_PARENT, so new networks only need one mapping update. * docs: update supported networks count and add Base to README and snapshot tests * docs: add Base to all network references across landing, legal, and test files * refactor: create canonical network palette and testnet utilities * chore: bump Node.js version to v24 in .nvmrc * chore: gitignore AI tool facades, plugins, and supabase local config * refactor: rename getNetworkTheme→getNetworkName, extract testnet utils, lowercase addresses * refactor: derive brand-tokens from palette, remove dead env vars, fix NetworkIcon a11y - NetworkTheme now aliases NetworkThemeName from network-palette (canonical source) - isValidNetworkTheme validates against NETWORK_PALETTE instead of NETWORK_THEMES - Remove 10 dead NEXT_PUBLIC_ALCHEMY/INFURA_*_URL env vars (RPC proxy uses API keys + slug maps) - NetworkIcon resolves testnet chain IDs to mainnet for icon/color/letter lookup - Add aria-label to both branded and fallback NetworkIcon paths - Export NETWORK_PALETTE and NetworkThemeName from shared/ui public API * refactor: derive network-themes from canonical palette + withTestnets * refactor: update consumers to use getNetworkThemeName, hoist widget colors * feat: add Base demo invoice, fix tokenAddress not clearing for native tokens Add 5th demo invoice for Base network (USDC, pending status) to landing page carousel. Fix react-hook-form reset() not clearing tokenAddress when loading native token templates (ETH/POL) — undefined must be mapped to '' so RHF treats it as an explicit value rather than "keep current". * fix: address PR review findings — remove unverified USDT, harden env, stabilize snapshots - Remove Base USDT token (no official Tether deployment on Base) - Add BLOCK_EXPLORERS comment explaining withTestnets exclusion - Update Base Sepolia block anchor from live RPC (28M → 39.88M) - Replace Math.random() with crypto.randomUUID() in RPC proxy - Harden validateEnv to throw in production on missing vars - Add Radix UI snapshot serializer for stable aria-controls IDs * fix: prevent stale total when switching tokens, add replaceDraft for clean data loading Total was stored as pre-calculated atomic units tied to a specific token's decimals. Switching tokens reconverted line item rates but left total stale, causing the preview to format ETH-scale values with USDC decimals (e.g. 5,510,000,000,000 instead of 5.80). - Add replaceDraft() for atomic draft replacement (hash decode, template load) - Extract toInvoiceItems/draftWithItems helpers, DRY 4 line item methods - Clear stale total on: token switch, item mutations, template save/load - Strip total from hash decode in CreateWorkspace (editor recalculates) - Handle string quantities in invoiceItemsToLineItems (old localStorage) * fix(history): resolve testnet networks showing as "Unknown" in history badges Use getNetworkName() for O(1) lookup across all networks instead of NETWORK_CONFIG.find() which only covered mainnets. Wrap NETWORK_BADGES_DARK with withTestnets() so testnet badges inherit parent network brand colors. * fix(create): reset all draft fields on form clear, extract store→form adapter draftSyncStatus leaked through reset because createNewDraft/clearDraft/replaceDraft didn't explicitly set it to 'idle'. Tax/discount/notes leaked because react-hook-form treats undefined in reset() as "keep previous value". Extract draftDataToFormValues() adapter as single source of truth for PartialInvoice→InvoiceFormValues conversion, replacing duplicated 60-line inline mappings. All optional string fields now coerced to '' on reset. * fix(test): align NetworkBadge test with getNetworkName fallback to chain ID * feat: update comparison table data to April 2026 research RF pricing changed to \$250+/mo subscription, data storage corrected to Centralized (hybrid API + on-chain, not pure IPFS), KYC/KYB updated to required (yes). Disclaimer and comment block updated to April 2026. * feat: add comparison page content data (VP vs Request Finance) * feat: add /compare/request-finance comparison page * feat: add /compare pages priority to sitemap config * feat: add link to detailed comparison from landing table * test: add comparison page tests * fix: improve comparison page UI and remove duplicate footer Apply UI/UX audit improvements: text-pretty headings, tabular-nums table, hover states, glow CTA button, visual star rating, TL;DR label, violet accent on bottom-line boxes. Remove duplicate footer links since app-level footer already exists. * ci: add project-sync workflow for auto VP Roadmap sync New issues automatically added to VP Roadmap project board with fields (Status, Priority, Advisor, Type, Source Repo) parsed from labels. Agents no longer need manual item-add. * fix(ci): use GraphQL API for project-sync workflow gh project item-add/item-edit fail with "unknown owner type" on user-level projects. Switch to direct GraphQL mutations. * chore: add .superpowers/ to gitignore * fix: invoice generation bugs — flash, source immutability, cross-tab sync (#105) * fix: prevent invoice flash on generate, preserve source immutability, add cross-tab sync - Remove clearDraft setTimeout that caused visible flash during navigation - Make TrackedInvoice.source immutable (first-write-wins) so visiting /pay doesn't overwrite 'created' to 'received' - Add localStorage storage event listener for cross-tab store rehydration * fix(ui): add cursor-pointer to CreatorHintBanner dismiss button * fix(store): key TrackedInvoice by contentHash (SHA-256) instead of invoiceId (#112) * feat(codec): add computeContentHash — SHA-256 bytes32 digest for invoice identity * feat(codec): return contentHash from parseInvoiceHash * feat(store): key TrackedInvoice by contentHash instead of invoiceId * feat(create): compute contentHash on invoice generation * feat(view): compute and expose contentHash from useInvoiceView * feat(import): compute contentHash for imported invoices * refactor(ui): wire contentHash through component hierarchy * refactor(payment): all hooks key by contentHash instead of invoiceId Updates SmartPayButtonProps, UsePaymentFlowParams, UsePaymentVerificationParams, UseFinalizationTrackerParams, UsePaymentPollingParams, and UseManualVerifyParams to accept contentHash. All store action calls (setTxHash, setError, setValidated, setFinalized, resetPaymentState, setConfirmations) now use contentHash as the key. Internal polling helpers (loops, visibility-handler) updated consistently. * fix: use contentHash key in polling params * test: update all tests for contentHash-based store key * fix: review fixes — runtime bugs, security hardening, perf improvements - Fix PaymentPanel using invoiceId instead of contentHash for store lookup (BUG-01: PDF export lost paidAt) - Fix DevStatusToggle passing invoiceId to contentHash-keyed store methods (BUG-02) - Use Promise.allSettled in migration to survive partial failures (S-01) - Always recompute contentHash on import, never trust pre-supplied values (S-02) - Add empty fragment guard in addToHistory (H-1) - Early return in setTxHash for unknown invoice (M-2) - Add console.warn to migration catch block (F-04) - Parallelize decode + hash in parseInvoiceHash via Promise.all - Parallelize import hash computation, eliminate in-place mutation * fix: resolve history page flickering and infinite migration loop - Replace non-reactive hasHydrated() with useStoreHydrated() hook that subscribes via onFinishHydration for proper React re-render on hydration - Make persist migration synchronous to avoid zustand v5 hydrationVersion race condition that cancelled in-flight async migrations - Compute contentHash post-hydration via onFinishHydration + hasHydrated guard to handle both sync and async hydration paths - Remove cross-tab storage event listener that triggered rehydrate() loops from stale tabs still writing version 1 * fix: show full invoice data in debug panel instead of decode flag * fix: skip post-hydration hash computation on v2+ stores Add _pendingHashComputation flag set only by migrate() during v1→v2 transition. _computeMissingContentHashes() now exits immediately on v2+ stores instead of reading store state on every hydration. * fix: remove console.info logs and fix test type errors Remove informational console logs from TrackedInvoiceStore (keep warnings). Add missing contentHash to SmartPayButton test fixtures. Add scrollMargin to MockIntersectionObserver for TS 5.5+ compat. * refactor: replace async crypto.subtle with sync @noble/hashes for SHA-256 Async two-phase migration (sync migrate → async post-hydration hash) caused store data loss: zustand persisted entries with empty contentHash between phases, and any failure in the async phase dropped invoices. Switch to sync SHA-256 via @noble/hashes (already a dependency via viem) so contentHash is computed atomically inside migrate(). Removes ~55 lines of async infrastructure: _pendingHashComputation, _computeMissingContentHashes, _sha256, onFinishHydration/hasHydrated fallback. * docs: fix SECURITY.md — styled-components → inline style injection, add /api/health to out-of-scope * fix(wallet): sync connection state between scoped Web3Providers LazyWalletButton in the header could stay in static placeholder state ("Connect") while PayButton's scoped provider already had the wallet connected. Root cause: LazyWalletButton only checked localStorage on mount and had no way to detect connections from other providers. Add WalletStateSync component that dispatches a custom DOM event on wallet connect, and a listener in LazyWalletButton to activate when the event fires. * fix(wallet): prevent rehydration race in scoped Web3Providers Multiple WagmiProvider instances sharing one wagmiConfig caused connector state corruption: each mount triggered rehydrate() which overwrote live connector instances with serialized plain objects from localStorage. Between rehydrate() and reconnect() completing, writeContract/sendTransaction crashed with "getChainId is not a function" because the connector lacked methods. Use WagmiContext.Provider (context-only, no hydration) for all Web3Provider instances after the first one. A module-level flag ensures only the primary instance triggers full WagmiProvider hydration + reconnect. * fix(payment): keyframe rotate to prevent SmartPay spinner freeze on Rabby framer-motion v12 with WAAPI backend stalls single-value rotate loops on the second iteration when a wallet extension's content script forces a re-render mid-mount. The breathing label kept animating (keyframes array) while the spinner icon froze (single value 360). Switching to explicit keyframes [0, 360] gives WAAPI an unambiguous start/end on every iteration and matches the pattern already used by FluidOverlay for all other infinite loops in the button tree. * fix(history): batch-check unpaid for both created and received invoices Parametrize useBatchCheck by invoice source so the History page can verify pending payments for both own and counterparty invoices, not just created. Add a Check Unpaid button to the Received section mirroring the Created one. Make invoice number and counterparty name in InvoiceCard clickable — both trigger the View action with hover/focus styling. * build(deps): bump viem from 2.47.10 to 2.47.16 (#122) Bumps [viem](https://github.com/wevm/viem) from 2.47.10 to 2.47.16. - [Release notes](https://github.com/wevm/viem/releases) - [Commits](https://github.com/wevm/viem/compare/viem@2.47.10...viem@2.47.16) --- updated-dependencies: - dependency-name: viem dependency-version: 2.47.16 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps-dev): bump typescript-eslint from 8.58.0 to 8.58.2 (#124) Bumps [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint) from 8.58.0 to 8.58.2. - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-eslint/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.58.2/packages/typescript-eslint) --- updated-dependencies: - dependency-name: typescript-eslint dependency-version: 8.58.2 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump @noble/hashes from 2.0.1 to 2.2.0 (#125) Bumps [@noble/hashes](https://github.com/paulmillr/noble-hashes) from 2.0.1 to 2.2.0. - [Release notes](https://github.com/paulmillr/noble-hashes/releases) - [Commits](https://github.com/paulmillr/noble-hashes/compare/2.0.1...2.2.0) --- updated-dependencies: - dependency-name: "@noble/hashes" dependency-version: 2.2.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps-dev): bump prettier from 3.7.4 to 3.8.2 (#126) Bumps [prettier](https://github.com/prettier/prettier) from 3.7.4 to 3.8.2. - [Release notes](https://github.com/prettier/prettier/releases) - [Changelog](https://github.com/prettier/prettier/blob/main/CHANGELOG.md) - [Commits](https://github.com/prettier/prettier/compare/3.7.4...3.8.2) --- updated-dependencies: - dependency-name: prettier dependency-version: 3.8.2 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump use-debounce from 10.0.6 to 10.1.1 (#127) Bumps [use-debounce](https://github.com/xnimorz/use-debounce) from 10.0.6 to 10.1.1. - [Release notes](https://github.com/xnimorz/use-debounce/releases) - [Changelog](https://github.com/xnimorz/use-debounce/blob/master/CHANGELOG.md) - [Commits](https://github.com/xnimorz/use-debounce/commits) --- updated-dependencies: - dependency-name: use-debounce dependency-version: 10.1.1 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump hono in the npm_and_yarn group across 1 directory (#104) Bumps the npm_and_yarn group with 1 update in the / directory: [hono](https://github.com/honojs/hono). Updates `hono` from 4.12.9 to 4.12.12 - [Release notes](https://github.com/honojs/hono/releases) - [Commits](https://github.com/honojs/hono/compare/v4.12.9...v4.12.12) --- updated-dependencies: - dependency-name: hono dependency-version: 4.12.12 dependency-type: indirect dependency-group: npm_and_yarn ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump react-hook-form from 7.70.0 to 7.72.1 (#130) Bumps [react-hook-form](https://github.com/react-hook-form/react-hook-form) from 7.70.0 to 7.72.1. - [Release notes](https://github.com/react-hook-form/react-hook-form/releases) - [Changelog](https://github.com/react-hook-form/react-hook-form/blob/master/CHANGELOG.md) - [Commits](https://github.com/react-hook-form/react-hook-form/compare/v7.70.0...v7.72.1) --- updated-dependencies: - dependency-name: react-hook-form dependency-version: 7.72.1 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps-dev): bump @tailwindcss/postcss from 4.1.18 to 4.2.2 (#131) Bumps [@tailwindcss/postcss](https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/@tailwindcss-postcss) from 4.1.18 to 4.2.2. - [Release notes](https://github.com/tailwindlabs/tailwindcss/releases) - [Changelog](https://github.com/tailwindlabs/tailwindcss/blob/main/CHANGELOG.md) - [Commits](https://github.com/tailwindlabs/tailwindcss/commits/v4.2.2/packages/@tailwindcss-postcss) --- updated-dependencies: - dependency-name: "@tailwindcss/postcss" dependency-version: 4.2.2 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps-dev): bump lucide-static from 1.7.0 to 1.8.0 (#123) Bumps [lucide-static](https://github.com/lucide-icons/lucide) from 1.7.0 to 1.8.0. - [Release notes](https://github.com/lucide-icons/lucide/releases) - [Commits](https://github.com/lucide-icons/lucide/compare/1.7.0...1.8.0) --- updated-dependencies: - dependency-name: lucide-static dependency-version: 1.8.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump @tanstack/react-query from 5.96.2 to 5.99.0 (#128) Bumps [@tanstack/react-query](https://github.com/TanStack/query/tree/HEAD/packages/react-query) from 5.96.2 to 5.99.0. - [Release notes](https://github.com/TanStack/query/releases) - [Changelog](https://github.com/TanStack/query/blob/main/packages/react-query/CHANGELOG.md) - [Commits](https://github.com/TanStack/query/commits/@tanstack/react-query@5.99.0/packages/react-query) --- updated-dependencies: - dependency-name: "@tanstack/react-query" dependency-version: 5.99.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps-dev): bump @types/node from 25.5.2 to 25.6.0 (#132) Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 25.5.2 to 25.6.0. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node) --- updated-dependencies: - dependency-name: "@types/node" dependency-version: 25.6.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps-dev): bump @next/eslint-plugin-next from 16.2.2 to 16.2.3 (#134) Bumps [@next/eslint-plugin-next](https://github.com/vercel/next.js/tree/HEAD/packages/eslint-plugin-next) from 16.2.2 to 16.2.3. - [Release notes](https://github.com/vercel/next.js/releases) - [Changelog](https://github.com/vercel/next.js/blob/canary/release.js) - [Commits](https://github.com/vercel/next.js/commits/v16.2.3/packages/eslint-plugin-next) --- updated-dependencies: - dependency-name: "@next/eslint-plugin-next" dependency-version: 16.2.3 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * feat(payment): typed wagmi error handling + onReplaced support (#115) * feat(payment): typed wagmi error handling + onReplaced support Replace fragile string-matching error classification with typed detection via viem's BaseError.walk() across the payment and wallet-connect features. Add onReplaced callback to handle user speedup/cancel of pending transactions. Component A: shared/lib/web3-errors - New module with isUserRejected, isInsufficientFunds, isChainMismatch, isReceiptNotFound, isReceiptTimeout, isTxReverted, walkCause - Walks BaseError cause chain via viem's typed API, falls back to string matching for non-BaseError edge cases (mobile WalletConnect) - 38 unit tests covering direct, wrapped, and fallback paths Component B: classifier refactor - classify-error.ts rewritten to use typed detectors before string matching - Removed step-based NETWORK_SWITCH_FAILED fallback — was masking user rejections of network switches - Added TX_REPLACED to PaymentErrorType + ERROR_MESSAGES entry - CANCELED_COPY constant for message unification - connection-error.ts now calls isUserRejected first for typed detection Component C: payment flow integration - use-payment-flow.ts: console.error moved below USER_REJECTED early return (fixes verbose wagmi stack in console on user cancel) - useWaitForTransactionReceipt now receives onReplaced callback: - reason 'cancelled' → toast + RESET (user intent) - reason 'replaced'/'repriced' → update hash + continue - New REPLACED reducer action for hash swap during confirming state - use-payment-verification.ts: sanitize raw viem errors through formatErrorMessage before writing to store + onReplaced observability * refactor(payment): address review feedback on typed wagmi error handling - Drop unused _step parameter from classifyPaymentError (dead arg after step-based fallback removal); update call site and 20+ test cases. - Fix incorrect comment in usePaymentVerification onReplaced — both hooks consume useWaitForTransactionReceipt in parallel, not sequentially. - Add TransactionExecutionError coverage to detect.test.ts (revert vs OOG shortMessage branches). * feat(payment-panel): persistent network chip across all states Adds a branded NetworkIcon + name chip at the top of PaymentPanel so payers always see which chain the payment targets — visible in pending, paid, paid-fallback and overdue states. Reserves right-side space via pr-12 to avoid overlap with the minimize button. Also migrates AmountDisplay assertions from toBeDefined() to toBeInTheDocument() per testing rules. * refactor(payment-panel): anchor network chip to amount, own minimize button Move the network chip from the panel header into each state's heading row (Total Due / Payment Successful / Expired / paid-fallback) so it sits beside the amount it qualifies — semantically tying chain to value instead of floating in an empty header strip. Extract NetworkChip into a shared presentational component to drop duplication across states. Pull the minimize button into PaymentPanel behind an onMinimize prop, removing the duplicated absolute overlay from PayWorkspace and InvoiceWorkspace. The button now coordinates with the pr-12 right-side clearance baked into every heading row. * fix(history): network icons, button sizing, robust template flow - NetworkBadge: render NetworkIcon (web3icons) before name - InvoiceCard: match Confirm/Cancel button height to regular buttons (min-h-[44px] py-2.5) to prevent layout shift on delete toggle - InvoiceList: replace fragile duplicateFromUrl + setState + push flow with hash-based navigation /create?template=1#<hash> - CreateWorkspace: detect ?template=1 and reset issuedAt/dueAt/total/ magicDust after replaceDraft so templates start with fresh dates - Remove unused duplicate-invoice.ts and its test mock * refactor(payment-panel): group network chip with due/paid date Relocates NetworkChip into a compact metadata row next to the due date (pending) or relative paidAt (paid/expired). Drops the "TOTAL DUE" label — the amount is self-explanatory and the label created a "Total Due ... Due May 2" tautology with the date chunk. - pending: [chip] Due <date> above the amount - paid: [chip] Funds sent · <relative> under Payment Successful - expired: [chip] Was due <date> · Payment disabled under header Adds formatRelativeTime() in shared/lib/date-time for ISO → "Just now" / "5 min ago" / "2 h ago" rendering. PaymentPanel now subscribes to tracked paidAt via a store selector so the subtitle reactively updates when the payment transitions to paid. Clears the chip out of the emerald amount accent box on paid state — zinc chip no longer clashes with the emerald tint. * fix(wallet): visible loading state during wagmi reconnect SmartPayButton and WalletButton both appeared frozen while wagmi restored the persisted connection: the pay button stayed on "Pay X Y" while disabled, and the header wallet button was hidden via opacity:0 so clicks fell through. Now both surfaces render an explicit disabled "Reconnecting…" state with a visible spinner and aria-busy. Covered by 6 new tests (3 SmartPayButton reconnect cases, 3 WalletButton). * fix(wallet): cover SSR pre-hydration gap in pay + header buttons Two bugs under one symptom ("click during page-load race gets stuck at Connecting"): 1. Pre-hydration gap: wagmi with `ssr: true` reports `status: 'disconnected'` on the first client render even when a persisted connection exists in localStorage. `isReconnecting` is false in that window, so the previous fix did not catch it — SmartPayButton flashed a clickable "Connect Wallet" and WalletButton did the same in the header. 2. Stuck-at-connecting race: when a user clicked through the flash, `handlePay` entered `connecting` and opened the Rainbow modal. Meanwhile wagmi finished the background reconnect. The lifecycle effect in `usePaymentFlow` checked `connectModalOpen` before `isConnected`, so if Rainbow's modal state didn't cleanly flip through the expected order the flow stayed in `connecting` forever. Fix: - New shared hook `useWagmiHydrating` detects pre-hydration (persisted connector id in localStorage + wagmi still on initial disconnected), plus the normal `connecting` / `reconnecting` statuses. Drops the pre-hydration heuristic once wagmi leaves the initial snapshot so later manual disconnect/reconnect cycles behave normally. - SmartPayButton and WalletButton now use `useWagmiHydrating` instead of `isReconnecting`. Both render a disabled loading button with aria-busy=true across the whole hydration window. - `usePaymentFlow` connecting effect now checks `isConnected` before `connectModalOpen`, so a background reconnect always wins and the flow cannot strand in `connecting`. - Regression tests: reorder-safe race in `use-payment-flow`, pre-hydration coverage in SmartPayButton + WalletButton suites. 387 payment + wallet-connect tests green. * fix(payment): cap wait-for-receipt timeout at 60s, disable retry Ensures a stuck transaction surfaces a user-visible RPC_ERROR banner within one block window instead of hanging on the spinner. Previously, viem's 180s default timeout combined with TanStack Query's default retry (3) meant the first user-visible error could be delayed by up to 9 minutes. Also drops the TEMP DEBUG console.logs added during manual test verification — all three test paths (USER_REJECTED silence, onReplaced cancel, onReplaced speedup) have been validated on Eth Sepolia + Rabby. Part of PR #115. * fix(payment): raise wait-for-receipt timeout to viem default 180s 60s was too aggressive — near-zero-gas transactions legitimately need several blocks on L1 before inclusion. Combined with retry: 0 this still caps the hidden wait at 3 minutes (vs viem's default retry × 180s = 9 minutes that motivated the original fix). Field-verified on Base Sepolia: a stuck tx now surfaces the RPC_ERROR banner as expected — only thing that needed tuning was the ceiling. Part of PR #115. * fix(payment-panel): make error banner X button clickable and cursor visible Tailwind v4 dropped the default pointer cursor on <button>, and dismissError only cleared the store — local paymentError stayed set, so the X appeared dead. Add cursor-pointer + type=button, and wire a composite handler that clears both paymentError and the tracked-invoice store error. * refactor(payment): simplify PR #115 after parallel review Findings from three parallel review agents (reuse, quality, efficiency) aggregated and fixed: - Remove dead TX_REPLACED PaymentErrorType: defined but never emitted (onReplaced dispatches REPLACED/RESET directly, classifier never returns it) - Remove walkCause from web3-errors barrel export: internal-only, test file imports from ../detect - Memoize onReplaced + extract RECEIPT_QUERY_OPTIONS/TIMEOUT_MS to module level in use-payment-flow.ts (inline refs were re-subscribing TanStack Query / viem watcher every render during confirming step) - Hoist stateless handleVerificationReplaced + memoize receiptQuery in use-payment-verification.ts (compounded by useBlockNumber watch: true) - Unwrap naked <div> wrapper with no props/layout in WalletButton.tsx - Fix misleading CANCELED_COPY comment (claimed cross-feature usage that never existed) Follow-ups tracked in #120 (NetworkChip/NetworkBadge unification), #121 (nowUnix migration). Net: -71 / +66 lines. Type-check, lint, 277 affected tests pass. * fix(payment): address PR #115 review findings - use receipt.transactionHash on CONFIRMED so replaced/repriced tx hashes aren't overwritten by the stale wagmi send hash - REPLACED reducer explicitly clears error for future-proofing - console.error logs shortMessage only to avoid leaking calldata if observability is wired later - use-payment-verification: consolidate imports above function decl - add reducer test covering REPLACED error preservation * fix(payment): correct block-time drift breaking creator-side verification Root cause: AVG_BLOCK_TIME_MS[11155111] was 12_000 but Sepolia actually runs ~13s/block. Over 35 days of forward drift estimateFromBlockHex returned a block above the real chain head; alchemy_getAssetTransfers returned empty and creators saw "payment not found" on confirmed transactions. Arbitrum Sepolia had the same class of bug (250ms assumed vs ~286ms measured). - AVG_BLOCK_TIME_MS: Sepolia 12000→13000, Arb Sepolia 250→286 (measured via 10k-block samples across all 10 supported chains). REFERENCE_BLOCKS left frozen — v1.0 shipped Mar 28, old invoices must decode with the same calibration they were created with. - /api/transfers: defense-in-depth safety net. Fetches eth_blockNumber in parallel with the transfers query, and on drifted client fromBlock retries with a 3-day lookback anchored to the real chain head. Drift logged via console.warn for observability. Eliminates the bug class regardless of anchor staleness. - scripts/measure-block-times.ts + pnpm check:block-drift: diagnostic that measures real avgBlockTime for every chain, compares vs hardcoded values, reports lookback margin, and exits non-zero on BROKEN verdict. - Route tests updated for the new parallel fetch; added cases covering both retry and no-retry paths of the …
ignromanov
added a commit
that referenced
this pull request
Jun 6, 2026
… a11y 84→100 + video captions (#302) * perf(landing): inline render-blocking CSS via experimental.inlineCss Enables Next.js experimental.inlineCss so the 3 stylesheet requests that blocked the first render (global Tailwind 21.5KB + 2 component chunks 2.1/2.4KB) are merged into a single <style> tag in <head>. PSI target: #2 render-blocking-resources, ~600ms LCP+FCP savings. CSP already allows unsafe-inline for style-src — no CSP change needed. Build evidence: index.html head now contains <style data-precedence="next" data-href="531c... b063... 67c5..."> with full Tailwind + component CSS inlined. Zero <link rel="stylesheet"> blocking tags remain. * perf(landing): add modern browserslist to eliminate SWC polyfills Targets chrome 111, safari 16.4, firefox 128, edge 111 — all ES2022-class, matching the Telegram/Meta/X WebViews from spec 073 IAB gate. Without an explicit browserslist Next.js ships SWC polyfills (Object.assign, Object.fromEntries, globalThis shims etc.). These four targets already support all ES2022 features natively so SWC emits no polyfill helpers. PSI target: #3 legacy JS, ~12KB gzip / ~150ms savings off chunk 5028. Verified: `npx browserslist` resolves to exactly {chrome 111, edge 111, firefox 128, safari 16.4}. * fix(a11y): add accessible names to nav links and wallet button * fix(a11y): add role=img to NetworkIcon spans * fix(a11y): improve caption contrast and remove superfluous figcaption * feat(landing): add video captions VTT track and DOM transcript * fix(landing): correct overlapping VTT cue timing
ignromanov
added a commit
that referenced
this pull request
Jun 6, 2026
…303) * docs: update privacy policy with Umami analytics details Add dedicated "Product Analytics" section, add Umami to Third-Party Services, fix misleading "Analytics or telemetry" item in "What We Don't Collect" section. * fix(demo): correct demo invoice data and native token template loading - Fix txHash #1 missing 2 hex chars (62→64 hex digits) - Remove redundant "(40 hours)" from description where qty=40 - Change Invoice #2 discount from 8% to 5% so tax/discount don't cancel out - Fix native token (ETH, POL) not recognized when loading invoice as template: spread merge didn't clear default tokenAddress when decoded data omits the key * docs: add community files, security policy, README redesign - LICENSE (MIT) - SECURITY.md + public/.well-known/security.txt (RFC 9116) - CONTRIBUTING.md, CODE_OF_CONDUCT.md (Contributor Covenant v2.1) - README.md full redesign: badges, How It Works, features, quick start - .github/FUNDING.yml (GitHub Sponsors + Giveth) - .github/dependabot.yml (weekly npm, monthly GHA) - .github/pull_request_template.md - .github/ISSUE_TEMPLATE/feature_request.md * fix(docs): simplify PR template to match existing style Summary + Test plan (lowercase), no generic checklist — CI handles validation. * fix(docs): PR template with structured summary and specific test plan Matches PR #45 style: subsections for larger PRs, concrete test checkboxes. * ci: add Dependabot auto-merge for patch and minor updates Auto-approve and squash-merge Dependabot PRs for patch/minor versions after CI passes. Major version updates require manual review. * build(deps-dev): bump tailwindcss from 4.1.18 to 4.2.2 (#70) Bumps [tailwindcss](https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/tailwindcss) from 4.1.18 to 4.2.2. - [Release notes](https://github.com/tailwindlabs/tailwindcss/releases) - [Changelog](https://github.com/tailwindlabs/tailwindcss/blob/main/CHANGELOG.md) - [Commits](https://github.com/tailwindlabs/tailwindcss/commits/v4.2.2/packages/tailwindcss) --- updated-dependencies: - dependency-name: tailwindcss dependency-version: 4.2.2 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump tailwind-merge from 3.4.0 to 3.5.0 (#62) Bumps [tailwind-merge](https://github.com/dcastil/tailwind-merge) from 3.4.0 to 3.5.0. - [Release notes](https://github.com/dcastil/tailwind-merge/releases) - [Commits](https://github.com/dcastil/tailwind-merge/compare/v3.4.0...v3.5.0) --- updated-dependencies: - dependency-name: tailwind-merge dependency-version: 3.5.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump zustand from 5.0.9 to 5.0.12 (#68) Bumps [zustand](https://github.com/pmndrs/zustand) from 5.0.9 to 5.0.12. - [Release notes](https://github.com/pmndrs/zustand/releases) - [Commits](https://github.com/pmndrs/zustand/compare/v5.0.9...v5.0.12) --- updated-dependencies: - dependency-name: zustand dependency-version: 5.0.12 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps-dev): bump lint-staged from 16.2.7 to 16.4.0 (#61) Bumps [lint-staged](https://github.com/lint-staged/lint-staged) from 16.2.7 to 16.4.0. - [Release notes](https://github.com/lint-staged/lint-staged/releases) - [Changelog](https://github.com/lint-staged/lint-staged/blob/main/CHANGELOG.md) - [Commits](https://github.com/lint-staged/lint-staged/compare/v16.2.7...v16.4.0) --- updated-dependencies: - dependency-name: lint-staged dependency-version: 16.4.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump viem from 2.43.4 to 2.47.6 (#63) Bumps [viem](https://github.com/wevm/viem) from 2.43.4 to 2.47.6. - [Release notes](https://github.com/wevm/viem/releases) - [Commits](https://github.com/wevm/viem/compare/viem@2.43.4...viem@2.47.6) --- updated-dependencies: - dependency-name: viem dependency-version: 2.47.6 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps-dev): bump @next/eslint-plugin-next from 16.1.1 to 16.2.1 (#69) Bumps [@next/eslint-plugin-next](https://github.com/vercel/next.js/tree/HEAD/packages/eslint-plugin-next) from 16.1.1 to 16.2.1. - [Release notes](https://github.com/vercel/next.js/releases) - [Changelog](https://github.com/vercel/next.js/blob/canary/release.js) - [Commits](https://github.com/vercel/next.js/commits/v16.2.1/packages/eslint-plugin-next) --- updated-dependencies: - dependency-name: "@next/eslint-plugin-next" dependency-version: 16.2.1 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump zod from 4.3.4 to 4.3.6 (#66) Bumps [zod](https://github.com/colinhacks/zod) from 4.3.4 to 4.3.6. - [Release notes](https://github.com/colinhacks/zod/releases) - [Commits](https://github.com/colinhacks/zod/compare/v4.3.4...v4.3.6) --- updated-dependencies: - dependency-name: zod dependency-version: 4.3.6 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * fix(github): issue templates frontmatter, dependabot auto-merge workflow - Add name/about/title/assignees to issue templates so GitHub recognizes them - Create config.yml disabling blank issues with security advisory link - Replace dependabot-auto-merge.yml with simplified dependabot-automerge.yml * build(deps-dev): bump lucide-static from 0.577.0 to 1.7.0 (#67) Bumps [lucide-static](https://github.com/lucide-icons/lucide) from 0.577.0 to 1.7.0. - [Release notes](https://github.com/lucide-icons/lucide/releases) - [Commits](https://github.com/lucide-icons/lucide/compare/0.577.0...1.7.0) --- updated-dependencies: - dependency-name: lucide-static dependency-version: 1.7.0 dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps-dev): bump @types/node from 22.19.3 to 25.5.0 (#65) Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 22.19.3 to 25.5.0. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node) --- updated-dependencies: - dependency-name: "@types/node" dependency-version: 25.5.0 dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump actions/upload-artifact from 4 to 7 (#60) Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4 to 7. - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/v4...v7) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-version: '7' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump pnpm/action-setup from 4 to 5 (#59) Bumps [pnpm/action-setup](https://github.com/pnpm/action-setup) from 4 to 5. - [Release notes](https://github.com/pnpm/action-setup/releases) - [Commits](https://github.com/pnpm/action-setup/compare/v4...v5) --- updated-dependencies: - dependency-name: pnpm/action-setup dependency-version: '5' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump actions/checkout from 4 to 6 (#58) Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 6. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v4...v6) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump actions/cache from 4 to 5 (#57) Bumps [actions/cache](https://github.com/actions/cache) from 4 to 5. - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](https://github.com/actions/cache/compare/v4...v5) --- updated-dependencies: - dependency-name: actions/cache dependency-version: '5' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump actions/setup-node from 4 to 6 (#56) Bumps [actions/setup-node](https://github.com/actions/setup-node) from 4 to 6. - [Release notes](https://github.com/actions/setup-node/releases) - [Commits](https://github.com/actions/setup-node/compare/v4...v6) --- updated-dependencies: - dependency-name: actions/setup-node dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump picomatch from 2.3.1 to 2.3.2 (#55) Bumps [picomatch](https://github.com/micromatch/picomatch) from 2.3.1 to 2.3.2. - [Release notes](https://github.com/micromatch/picomatch/releases) - [Changelog](https://github.com/micromatch/picomatch/blob/master/CHANGELOG.md) - [Commits](https://github.com/micromatch/picomatch/compare/2.3.1...2.3.2) --- updated-dependencies: - dependency-name: picomatch dependency-version: 2.3.2 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps-dev): bump vitest and @vitest/coverage-istanbul (#64) Bumps [vitest](https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest) and [@vitest/coverage-istanbul](https://github.com/vitest-dev/vitest/tree/HEAD/packages/coverage-istanbul). These dependencies needed to be updated together. Updates `vitest` from 4.0.16 to 4.1.2 - [Release notes](https://github.com/vitest-dev/vitest/releases) - [Commits](https://github.com/vitest-dev/vitest/commits/v4.1.2/packages/vitest) Updates `@vitest/coverage-istanbul` from 4.0.16 to 4.1.2 - [Release notes](https://github.com/vitest-dev/vitest/releases) - [Commits](https://github.com/vitest-dev/vitest/commits/v4.1.2/packages/coverage-istanbul) --- updated-dependencies: - dependency-name: vitest dependency-version: 4.1.2 dependency-type: direct:development update-type: version-update:semver-minor - dependency-name: "@vitest/coverage-istanbul" dependency-version: 4.1.2 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump the npm_and_yarn group across 1 directory with 11 updates (#71) Bumps the npm_and_yarn group with 11 updates in the / directory: | Package | From | To | | --- | --- | --- | | [next](https://github.com/vercel/next.js) | `15.5.9` | `15.5.14` | | [happy-dom](https://github.com/capricorn86/happy-dom) | `20.0.11` | `20.8.9` | | [ajv](https://github.com/ajv-validator/ajv) | `6.12.6` | `6.14.0` | | [axios](https://github.com/axios/axios) | `1.13.2` | `1.14.0` | | [brace-expansion](https://github.com/juliangruber/brace-expansion) | `1.1.12` | `1.1.13` | | [flatted](https://github.com/WebReflection/flatted) | `3.3.3` | `3.4.2` | | [h3](https://github.com/h3js/h3) | `1.15.4` | `1.15.10` | | [hono](https://github.com/honojs/hono) | `4.11.3` | `4.12.9` | | [minimatch](https://github.com/isaacs/minimatch) | `3.1.2` | `3.1.5` | | [rollup](https://github.com/rollup/rollup) | `4.54.0` | `4.60.1` | | [socket.io-parser](https://github.com/socketio/socket.io) | `4.2.5` | `4.2.6` | Updates `next` from 15.5.9 to 15.5.14 - [Release notes](https://github.com/vercel/next.js/releases) - [Changelog](https://github.com/vercel/next.js/blob/canary/release.js) - [Commits](https://github.com/vercel/next.js/compare/v15.5.9...v15.5.14) Updates `happy-dom` from 20.0.11 to 20.8.9 - [Release notes](https://github.com/capricorn86/happy-dom/releases) - [Commits](https://github.com/capricorn86/happy-dom/compare/v20.0.11...v20.8.9) Updates `ajv` from 6.12.6 to 6.14.0 - [Release notes](https://github.com/ajv-validator/ajv/releases) - [Commits](https://github.com/ajv-validator/ajv/compare/v6.12.6...v6.14.0) Updates `axios` from 1.13.2 to 1.14.0 - [Release notes](https://github.com/axios/axios/releases) - [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md) - [Commits](https://github.com/axios/axios/compare/v1.13.2...v1.14.0) Updates `brace-expansion` from 1.1.12 to 1.1.13 - [Release notes](https://github.com/juliangruber/brace-expansion/releases) - [Commits](https://github.com/juliangruber/brace-expansion/compare/v1.1.12...v1.1.13) Updates `flatted` from 3.3.3 to 3.4.2 - [Commits](https://github.com/WebReflection/flatted/compare/v3.3.3...v3.4.2) Updates `h3` from 1.15.4 to 1.15.10 - [Release notes](https://github.com/h3js/h3/releases) - [Changelog](https://github.com/h3js/h3/blob/v1.15.10/CHANGELOG.md) - [Commits](https://github.com/h3js/h3/compare/v1.15.4...v1.15.10) Updates `hono` from 4.11.3 to 4.12.9 - [Release notes](https://github.com/honojs/hono/releases) - [Commits](https://github.com/honojs/hono/compare/v4.11.3...v4.12.9) Updates `minimatch` from 3.1.2 to 3.1.5 - [Changelog](https://github.com/isaacs/minimatch/blob/main/changelog.md) - [Commits](https://github.com/isaacs/minimatch/compare/v3.1.2...v3.1.5) Updates `rollup` from 4.54.0 to 4.60.1 - [Release notes](https://github.com/rollup/rollup/releases) - [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md) - [Commits](https://github.com/rollup/rollup/compare/v4.54.0...v4.60.1) Updates `socket.io-parser` from 4.2.5 to 4.2.6 - [Release notes](https://github.com/socketio/socket.io/releases) - [Changelog](https://github.com/socketio/socket.io/blob/main/CHANGELOG.md) - [Commits](https://github.com/socketio/socket.io/compare/socket.io-parser@4.2.5...socket.io-parser@4.2.6) --- updated-dependencies: - dependency-name: next dependency-version: 15.5.14 dependency-type: direct:production dependency-group: npm_and_yarn - dependency-name: happy-dom dependency-version: 20.8.9 dependency-type: direct:development dependency-group: npm_and_yarn - dependency-name: ajv dependency-version: 6.14.0 dependency-type: indirect dependency-group: npm_and_yarn - dependency-name: axios dependency-version: 1.14.0 dependency-type: indirect dependency-group: npm_and_yarn - dependency-name: brace-expansion dependency-version: 1.1.13 dependency-type: indirect dependency-group: npm_and_yarn - dependency-name: flatted dependency-version: 3.4.2 dependency-type: indirect dependency-group: npm_and_yarn - dependency-name: h3 dependency-version: 1.15.10 dependency-type: indirect dependency-group: npm_and_yarn - dependency-name: hono dependency-version: 4.12.9 dependency-type: indirect dependency-group: npm_and_yarn - dependency-name: minimatch dependency-version: 3.1.5 dependency-type: indirect dependency-group: npm_and_yarn - dependency-name: rollup dependency-version: 4.60.1 dependency-type: indirect dependency-group: npm_and_yarn - dependency-name: socket.io-parser dependency-version: 4.2.6 dependency-type: indirect dependency-group: npm_and_yarn ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump yaml from 2.8.2 to 2.8.3 (#53) Bumps [yaml](https://github.com/eemeli/yaml) from 2.8.2 to 2.8.3. - [Release notes](https://github.com/eemeli/yaml/releases) - [Commits](https://github.com/eemeli/yaml/compare/v2.8.2...v2.8.3) --- updated-dependencies: - dependency-name: yaml dependency-version: 2.8.3 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump @xmldom/xmldom (#72) Bumps the npm_and_yarn group with 1 update in the / directory: [@xmldom/xmldom](https://github.com/xmldom/xmldom). Updates `@xmldom/xmldom` from 0.8.11 to 0.8.12 - [Release notes](https://github.com/xmldom/xmldom/releases) - [Changelog](https://github.com/xmldom/xmldom/blob/master/CHANGELOG.md) - [Commits](https://github.com/xmldom/xmldom/compare/0.8.11...0.8.12) --- updated-dependencies: - dependency-name: "@xmldom/xmldom" dependency-version: 0.8.12 dependency-type: indirect dependency-group: npm_and_yarn ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * docs: add Drips FUNDING.json + fix Giveth URL in FUNDING.yml - FUNDING.json: Drips Network project claim (treasury wallet) - FUNDING.yml: correct Giveth project URL slug * Add newline at end of FUNDING.json Fix formatting by adding a newline at the end of the file. * docs: add OP Atlas projectId to FUNDING.json * docs: add Optimism network to Drips FUNDING.json * docs: add Buy Me a Coffee to FUNDING.yml * build(deps): bump lodash in the npm_and_yarn group across 1 directory (#78) Bumps the npm_and_yarn group with 1 update in the / directory: [lodash](https://github.com/lodash/lodash). Updates `lodash` from 4.17.21 to 4.18.1 - [Release notes](https://github.com/lodash/lodash/releases) - [Commits](https://github.com/lodash/lodash/compare/4.17.21...4.18.1) --- updated-dependencies: - dependency-name: lodash dependency-version: 4.18.1 dependency-type: indirect dependency-group: npm_and_yarn ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump defu in the npm_and_yarn group across 1 directory (#80) Bumps the npm_and_yarn group with 1 update in the / directory: [defu](https://github.com/unjs/defu). Updates `defu` from 6.1.4 to 6.1.6 - [Release notes](https://github.com/unjs/defu/releases) - [Changelog](https://github.com/unjs/defu/blob/main/CHANGELOG.md) - [Commits](https://github.com/unjs/defu/compare/v6.1.4...v6.1.6) --- updated-dependencies: - dependency-name: defu dependency-version: 6.1.6 dependency-type: indirect dependency-group: npm_and_yarn ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * fix: remove robots.txt (static export doesn't serve it) * feat: add 512x512 app icon for PWA and social sharing * feat: add TalentApp domain verification meta tag * build(deps): bump @tanstack/react-query from 5.90.16 to 5.96.2 (#82) Bumps [@tanstack/react-query](https://github.com/TanStack/query/tree/HEAD/packages/react-query) from 5.90.16 to 5.96.2. - [Release notes](https://github.com/TanStack/query/releases) - [Changelog](https://github.com/TanStack/query/blob/main/packages/react-query/CHANGELOG.md) - [Commits](https://github.com/TanStack/query/commits/@tanstack/react-query@5.96.2/packages/react-query) --- updated-dependencies: - dependency-name: "@tanstack/react-query" dependency-version: 5.96.2 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps-dev): bump @next/eslint-plugin-next from 16.2.1 to 16.2.2 (#84) Bumps [@next/eslint-plugin-next](https://github.com/vercel/next.js/tree/HEAD/packages/eslint-plugin-next) from 16.2.1 to 16.2.2. - [Release notes](https://github.com/vercel/next.js/releases) - [Changelog](https://github.com/vercel/next.js/blob/canary/release.js) - [Commits](https://github.com/vercel/next.js/commits/v16.2.2/packages/eslint-plugin-next) --- updated-dependencies: - dependency-name: "@next/eslint-plugin-next" dependency-version: 16.2.2 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump framer-motion from 12.23.26 to 12.38.0 (#87) Bumps [framer-motion](https://github.com/motiondivision/motion) from 12.23.26 to 12.38.0. - [Changelog](https://github.com/motiondivision/motion/blob/main/CHANGELOG.md) - [Commits](https://github.com/motiondivision/motion/compare/v12.23.26...v12.38.0) --- updated-dependencies: - dependency-name: framer-motion dependency-version: 12.38.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps-dev): bump @vitejs/plugin-react from 5.1.2 to 5.2.0 (#88) Bumps [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/tree/HEAD/packages/plugin-react) from 5.1.2 to 5.2.0. - [Release notes](https://github.com/vitejs/vite-plugin-react/releases) - [Changelog](https://github.com/vitejs/vite-plugin-react/blob/plugin-react@5.2.0/packages/plugin-react/CHANGELOG.md) - [Commits](https://github.com/vitejs/vite-plugin-react/commits/plugin-react@5.2.0/packages/plugin-react) --- updated-dependencies: - dependency-name: "@vitejs/plugin-react" dependency-version: 5.2.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps-dev): bump postcss from 8.5.6 to 8.5.8 (#89) Bumps [postcss](https://github.com/postcss/postcss) from 8.5.6 to 8.5.8. - [Release notes](https://github.com/postcss/postcss/releases) - [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md) - [Commits](https://github.com/postcss/postcss/compare/8.5.6...8.5.8) --- updated-dependencies: - dependency-name: postcss dependency-version: 8.5.8 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps-dev): bump typescript-eslint from 8.51.0 to 8.58.0 (#92) Bumps [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint) from 8.51.0 to 8.58.0. - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-eslint/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.58.0/packages/typescript-eslint) --- updated-dependencies: - dependency-name: typescript-eslint dependency-version: 8.58.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps-dev): bump @testing-library/react from 16.3.1 to 16.3.2 (#93) Bumps [@testing-library/react](https://github.com/testing-library/react-testing-library) from 16.3.1 to 16.3.2. - [Release notes](https://github.com/testing-library/react-testing-library/releases) - [Changelog](https://github.com/testing-library/react-testing-library/blob/main/CHANGELOG.md) - [Commits](https://github.com/testing-library/react-testing-library/compare/v16.3.1...v16.3.2) --- updated-dependencies: - dependency-name: "@testing-library/react" dependency-version: 16.3.2 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump @web3icons/react from 4.1.14 to 4.1.17 (#94) Bumps [@web3icons/react](https://github.com/0xa3k5/web3icons/tree/HEAD/packages/react) from 4.1.14 to 4.1.17. - [Release notes](https://github.com/0xa3k5/web3icons/releases) - [Changelog](https://github.com/0xa3k5/web3icons/blob/main/packages/react/CHANGELOG.md) - [Commits](https://github.com/0xa3k5/web3icons/commits/@web3icons/react@4.1.17/packages/react) --- updated-dependencies: - dependency-name: "@web3icons/react" dependency-version: 4.1.17 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump @upstash/ratelimit from 2.0.7 to 2.0.8 (#91) Bumps [@upstash/ratelimit](https://github.com/upstash/ratelimit) from 2.0.7 to 2.0.8. - [Release notes](https://github.com/upstash/ratelimit/releases) - [Commits](https://github.com/upstash/ratelimit/compare/v2.0.7...v2.0.8) --- updated-dependencies: - dependency-name: "@upstash/ratelimit" dependency-version: 2.0.8 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps-dev): bump @eslint/eslintrc from 3.3.3 to 3.3.5 (#96) Bumps [@eslint/eslintrc](https://github.com/eslint/eslintrc) from 3.3.3 to 3.3.5. - [Release notes](https://github.com/eslint/eslintrc/releases) - [Changelog](https://github.com/eslint/eslintrc/blob/main/CHANGELOG.md) - [Commits](https://github.com/eslint/eslintrc/compare/eslintrc-v3.3.3...eslintrc-v3.3.5) --- updated-dependencies: - dependency-name: "@eslint/eslintrc" dependency-version: 3.3.5 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump pixi.js from 8.14.3 to 8.17.1 (#100) Bumps [pixi.js](https://github.com/pixijs/pixijs) from 8.14.3 to 8.17.1. - [Release notes](https://github.com/pixijs/pixijs/releases) - [Commits](https://github.com/pixijs/pixijs/compare/v8.14.3...v8.17.1) --- updated-dependencies: - dependency-name: pixi.js dependency-version: 8.17.1 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump geist from 1.5.1 to 1.7.0 (#98) Bumps [geist](https://github.com/vercel/geist-font/tree/HEAD/packages/next) from 1.5.1 to 1.7.0. - [Release notes](https://github.com/vercel/geist-font/releases) - [Changelog](https://github.com/vercel/geist-font/blob/main/packages/next/CHANGELOG.md) - [Commits](https://github.com/vercel/geist-font/commits/geist@1.7.0/packages/next) --- updated-dependencies: - dependency-name: geist dependency-version: 1.7.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps-dev): bump @types/node from 25.5.0 to 25.5.2 (#99) Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 25.5.0 to 25.5.2. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node) --- updated-dependencies: - dependency-name: "@types/node" dependency-version: 25.5.2 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump viem from 2.47.6 to 2.47.10 (#97) Bumps [viem](https://github.com/wevm/viem) from 2.47.6 to 2.47.10. - [Release notes](https://github.com/wevm/viem/releases) - [Commits](https://github.com/wevm/viem/compare/viem@2.47.6...viem@2.47.10) --- updated-dependencies: - dependency-name: viem dependency-version: 2.47.10 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps-dev): bump @eslint/js from 9.39.2 to 9.39.4 (#101) Bumps [@eslint/js](https://github.com/eslint/eslint/tree/HEAD/packages/js) from 9.39.2 to 9.39.4. - [Release notes](https://github.com/eslint/eslint/releases) - [Commits](https://github.com/eslint/eslint/commits/v9.39.4/packages/js) --- updated-dependencies: - dependency-name: "@eslint/js" dependency-version: 9.39.4 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps-dev): bump vite in the npm_and_yarn group across 1 directory (#102) Bumps the npm_and_yarn group with 1 update in the / directory: [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite). Updates `vite` from 7.3.0 to 7.3.2 - [Release notes](https://github.com/vitejs/vite/releases) - [Changelog](https://github.com/vitejs/vite/blob/v7.3.2/packages/vite/CHANGELOG.md) - [Commits](https://github.com/vitejs/vite/commits/v7.3.2/packages/vite) --- updated-dependencies: - dependency-name: vite dependency-version: 7.3.2 dependency-type: direct:development dependency-group: npm_and_yarn ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * refactor(history): redesign history page cards with payment panel style (#103) * feat(history): add StatusGradientBar component * feat(history): add NetworkBadge component with tests * refactor(history): redesign InvoiceStatusBadge with dot + glow * refactor(history): restyle InvoiceCardShell with zinc-900 + gradient bar * refactor(history): rewrite HistoryList with new card layout, network badge, subtotal * refactor(history): rewrite ReceivedInvoiceList with unified card design + Template button * refactor(history): update HistoryWorkspace colors gray→zinc * fix(history): remove unused type imports in ReceivedInvoiceList * refactor(history): extract shared InvoiceCard, remove duplicate card components Unified HistoryEntryCard and ReceivedInvoiceCard (~95% identical) into a single InvoiceCard with a nameLabel prop. Removed defeated memo(), pointless useMemo, dead source prop, and unnecessary JSX comments. Collapsed identical DecodedReceivedInvoice type into alias for DecodedHistoryEntry. * refactor(history): consolidate duplicated configs, merge list components - Merge HistoryList + ReceivedInvoiceList into unified InvoiceList with variant prop ('created'|'received') controlling route, name, empty text - Extract INVOICE_STATUS_CHIPS to entities/invoice for shared status colors consumed by InvoiceStatusBadge (features) and StatusChip (widgets) - Move network badge dark-mode colors to entities/network (NETWORK_BADGES_DARK) - Add formatDateMedium, formatDateCompact, isoToUnix to shared/lib/date-time - Remove deprecated DecodedReceivedInvoice type alias - Net -54 lines, 59/59 tests pass, tsc + lint clean * feat: add Base network (8453) + refactor network visual system (#79) * fix: remove robots.txt (static export doesn't serve it) * feat: add BaseIcon SVG component for Base network * feat: add Base (8453) and Base Sepolia (84532) to chain config * feat: add Base network metadata and codes * feat: add Base token registry (ETH, USDC, USDT) * feat: add Base provider slugs for Alchemy and Infura * feat: add Base confirmation config (OP Stack) * feat: add Base block estimation parameters * feat: add Base UI theming, badges, glows, and explorer * feat: add Base RPC URL env vars to schema * fix: add Base to theme configs, update chain count tests and snapshots * fix: add Base to NetworkIcon component (web3icons + fallback) * fix: update Base reference block from live explorer data * refactor: remove unused BaseIcon (NetworkIcon uses @web3icons/react) * fix: boost Base glow opacity (blue is subtle on dark background) * revert: restore original Base glow values * fix: resolve testnet glow/shadow/badge lookups via withTestnets helper Visual config Records (NETWORK_SHADOWS, NETWORK_GLOWS, NETWORK_GLOW_SHADOWS, NETWORK_GLOW_BORDERS, NETWORK_BADGES) were keyed by mainnet chain IDs only, causing missing glow on testnet invoices (e.g. Base Sepolia 84532). Added withTestnets() helper that auto-derives testnet entries from TESTNET_PARENT, so new networks only need one mapping update. * docs: update supported networks count and add Base to README and snapshot tests * docs: add Base to all network references across landing, legal, and test files * refactor: create canonical network palette and testnet utilities * chore: bump Node.js version to v24 in .nvmrc * chore: gitignore AI tool facades, plugins, and supabase local config * refactor: rename getNetworkTheme→getNetworkName, extract testnet utils, lowercase addresses * refactor: derive brand-tokens from palette, remove dead env vars, fix NetworkIcon a11y - NetworkTheme now aliases NetworkThemeName from network-palette (canonical source) - isValidNetworkTheme validates against NETWORK_PALETTE instead of NETWORK_THEMES - Remove 10 dead NEXT_PUBLIC_ALCHEMY/INFURA_*_URL env vars (RPC proxy uses API keys + slug maps) - NetworkIcon resolves testnet chain IDs to mainnet for icon/color/letter lookup - Add aria-label to both branded and fallback NetworkIcon paths - Export NETWORK_PALETTE and NetworkThemeName from shared/ui public API * refactor: derive network-themes from canonical palette + withTestnets * refactor: update consumers to use getNetworkThemeName, hoist widget colors * feat: add Base demo invoice, fix tokenAddress not clearing for native tokens Add 5th demo invoice for Base network (USDC, pending status) to landing page carousel. Fix react-hook-form reset() not clearing tokenAddress when loading native token templates (ETH/POL) — undefined must be mapped to '' so RHF treats it as an explicit value rather than "keep current". * fix: address PR review findings — remove unverified USDT, harden env, stabilize snapshots - Remove Base USDT token (no official Tether deployment on Base) - Add BLOCK_EXPLORERS comment explaining withTestnets exclusion - Update Base Sepolia block anchor from live RPC (28M → 39.88M) - Replace Math.random() with crypto.randomUUID() in RPC proxy - Harden validateEnv to throw in production on missing vars - Add Radix UI snapshot serializer for stable aria-controls IDs * fix: prevent stale total when switching tokens, add replaceDraft for clean data loading Total was stored as pre-calculated atomic units tied to a specific token's decimals. Switching tokens reconverted line item rates but left total stale, causing the preview to format ETH-scale values with USDC decimals (e.g. 5,510,000,000,000 instead of 5.80). - Add replaceDraft() for atomic draft replacement (hash decode, template load) - Extract toInvoiceItems/draftWithItems helpers, DRY 4 line item methods - Clear stale total on: token switch, item mutations, template save/load - Strip total from hash decode in CreateWorkspace (editor recalculates) - Handle string quantities in invoiceItemsToLineItems (old localStorage) * fix(history): resolve testnet networks showing as "Unknown" in history badges Use getNetworkName() for O(1) lookup across all networks instead of NETWORK_CONFIG.find() which only covered mainnets. Wrap NETWORK_BADGES_DARK with withTestnets() so testnet badges inherit parent network brand colors. * fix(create): reset all draft fields on form clear, extract store→form adapter draftSyncStatus leaked through reset because createNewDraft/clearDraft/replaceDraft didn't explicitly set it to 'idle'. Tax/discount/notes leaked because react-hook-form treats undefined in reset() as "keep previous value". Extract draftDataToFormValues() adapter as single source of truth for PartialInvoice→InvoiceFormValues conversion, replacing duplicated 60-line inline mappings. All optional string fields now coerced to '' on reset. * fix(test): align NetworkBadge test with getNetworkName fallback to chain ID * feat: update comparison table data to April 2026 research RF pricing changed to \$250+/mo subscription, data storage corrected to Centralized (hybrid API + on-chain, not pure IPFS), KYC/KYB updated to required (yes). Disclaimer and comment block updated to April 2026. * feat: add comparison page content data (VP vs Request Finance) * feat: add /compare/request-finance comparison page * feat: add /compare pages priority to sitemap config * feat: add link to detailed comparison from landing table * test: add comparison page tests * fix: improve comparison page UI and remove duplicate footer Apply UI/UX audit improvements: text-pretty headings, tabular-nums table, hover states, glow CTA button, visual star rating, TL;DR label, violet accent on bottom-line boxes. Remove duplicate footer links since app-level footer already exists. * ci: add project-sync workflow for auto VP Roadmap sync New issues automatically added to VP Roadmap project board with fields (Status, Priority, Advisor, Type, Source Repo) parsed from labels. Agents no longer need manual item-add. * fix(ci): use GraphQL API for project-sync workflow gh project item-add/item-edit fail with "unknown owner type" on user-level projects. Switch to direct GraphQL mutations. * chore: add .superpowers/ to gitignore * fix: invoice generation bugs — flash, source immutability, cross-tab sync (#105) * fix: prevent invoice flash on generate, preserve source immutability, add cross-tab sync - Remove clearDraft setTimeout that caused visible flash during navigation - Make TrackedInvoice.source immutable (first-write-wins) so visiting /pay doesn't overwrite 'created' to 'received' - Add localStorage storage event listener for cross-tab store rehydration * fix(ui): add cursor-pointer to CreatorHintBanner dismiss button * fix(store): key TrackedInvoice by contentHash (SHA-256) instead of invoiceId (#112) * feat(codec): add computeContentHash — SHA-256 bytes32 digest for invoice identity * feat(codec): return contentHash from parseInvoiceHash * feat(store): key TrackedInvoice by contentHash instead of invoiceId * feat(create): compute contentHash on invoice generation * feat(view): compute and expose contentHash from useInvoiceView * feat(import): compute contentHash for imported invoices * refactor(ui): wire contentHash through component hierarchy * refactor(payment): all hooks key by contentHash instead of invoiceId Updates SmartPayButtonProps, UsePaymentFlowParams, UsePaymentVerificationParams, UseFinalizationTrackerParams, UsePaymentPollingParams, and UseManualVerifyParams to accept contentHash. All store action calls (setTxHash, setError, setValidated, setFinalized, resetPaymentState, setConfirmations) now use contentHash as the key. Internal polling helpers (loops, visibility-handler) updated consistently. * fix: use contentHash key in polling params * test: update all tests for contentHash-based store key * fix: review fixes — runtime bugs, security hardening, perf improvements - Fix PaymentPanel using invoiceId instead of contentHash for store lookup (BUG-01: PDF export lost paidAt) - Fix DevStatusToggle passing invoiceId to contentHash-keyed store methods (BUG-02) - Use Promise.allSettled in migration to survive partial failures (S-01) - Always recompute contentHash on import, never trust pre-supplied values (S-02) - Add empty fragment guard in addToHistory (H-1) - Early return in setTxHash for unknown invoice (M-2) - Add console.warn to migration catch block (F-04) - Parallelize decode + hash in parseInvoiceHash via Promise.all - Parallelize import hash computation, eliminate in-place mutation * fix: resolve history page flickering and infinite migration loop - Replace non-reactive hasHydrated() with useStoreHydrated() hook that subscribes via onFinishHydration for proper React re-render on hydration - Make persist migration synchronous to avoid zustand v5 hydrationVersion race condition that cancelled in-flight async migrations - Compute contentHash post-hydration via onFinishHydration + hasHydrated guard to handle both sync and async hydration paths - Remove cross-tab storage event listener that triggered rehydrate() loops from stale tabs still writing version 1 * fix: show full invoice data in debug panel instead of decode flag * fix: skip post-hydration hash computation on v2+ stores Add _pendingHashComputation flag set only by migrate() during v1→v2 transition. _computeMissingContentHashes() now exits immediately on v2+ stores instead of reading store state on every hydration. * fix: remove console.info logs and fix test type errors Remove informational console logs from TrackedInvoiceStore (keep warnings). Add missing contentHash to SmartPayButton test fixtures. Add scrollMargin to MockIntersectionObserver for TS 5.5+ compat. * refactor: replace async crypto.subtle with sync @noble/hashes for SHA-256 Async two-phase migration (sync migrate → async post-hydration hash) caused store data loss: zustand persisted entries with empty contentHash between phases, and any failure in the async phase dropped invoices. Switch to sync SHA-256 via @noble/hashes (already a dependency via viem) so contentHash is computed atomically inside migrate(). Removes ~55 lines of async infrastructure: _pendingHashComputation, _computeMissingContentHashes, _sha256, onFinishHydration/hasHydrated fallback. * docs: fix SECURITY.md — styled-components → inline style injection, add /api/health to out-of-scope * fix(wallet): sync connection state between scoped Web3Providers LazyWalletButton in the header could stay in static placeholder state ("Connect") while PayButton's scoped provider already had the wallet connected. Root cause: LazyWalletButton only checked localStorage on mount and had no way to detect connections from other providers. Add WalletStateSync component that dispatches a custom DOM event on wallet connect, and a listener in LazyWalletButton to activate when the event fires. * fix(wallet): prevent rehydration race in scoped Web3Providers Multiple WagmiProvider instances sharing one wagmiConfig caused connector state corruption: each mount triggered rehydrate() which overwrote live connector instances with serialized plain objects from localStorage. Between rehydrate() and reconnect() completing, writeContract/sendTransaction crashed with "getChainId is not a function" because the connector lacked methods. Use WagmiContext.Provider (context-only, no hydration) for all Web3Provider instances after the first one. A module-level flag ensures only the primary instance triggers full WagmiProvider hydration + reconnect. * fix(payment): keyframe rotate to prevent SmartPay spinner freeze on Rabby framer-motion v12 with WAAPI backend stalls single-value rotate loops on the second iteration when a wallet extension's content script forces a re-render mid-mount. The breathing label kept animating (keyframes array) while the spinner icon froze (single value 360). Switching to explicit keyframes [0, 360] gives WAAPI an unambiguous start/end on every iteration and matches the pattern already used by FluidOverlay for all other infinite loops in the button tree. * fix(history): batch-check unpaid for both created and received invoices Parametrize useBatchCheck by invoice source so the History page can verify pending payments for both own and counterparty invoices, not just created. Add a Check Unpaid button to the Received section mirroring the Created one. Make invoice number and counterparty name in InvoiceCard clickable — both trigger the View action with hover/focus styling. * build(deps): bump viem from 2.47.10 to 2.47.16 (#122) Bumps [viem](https://github.com/wevm/viem) from 2.47.10 to 2.47.16. - [Release notes](https://github.com/wevm/viem/releases) - [Commits](https://github.com/wevm/viem/compare/viem@2.47.10...viem@2.47.16) --- updated-dependencies: - dependency-name: viem dependency-version: 2.47.16 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps-dev): bump typescript-eslint from 8.58.0 to 8.58.2 (#124) Bumps [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint) from 8.58.0 to 8.58.2. - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-eslint/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.58.2/packages/typescript-eslint) --- updated-dependencies: - dependency-name: typescript-eslint dependency-version: 8.58.2 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump @noble/hashes from 2.0.1 to 2.2.0 (#125) Bumps [@noble/hashes](https://github.com/paulmillr/noble-hashes) from 2.0.1 to 2.2.0. - [Release notes](https://github.com/paulmillr/noble-hashes/releases) - [Commits](https://github.com/paulmillr/noble-hashes/compare/2.0.1...2.2.0) --- updated-dependencies: - dependency-name: "@noble/hashes" dependency-version: 2.2.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps-dev): bump prettier from 3.7.4 to 3.8.2 (#126) Bumps [prettier](https://github.com/prettier/prettier) from 3.7.4 to 3.8.2. - [Release notes](https://github.com/prettier/prettier/releases) - [Changelog](https://github.com/prettier/prettier/blob/main/CHANGELOG.md) - [Commits](https://github.com/prettier/prettier/compare/3.7.4...3.8.2) --- updated-dependencies: - dependency-name: prettier dependency-version: 3.8.2 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump use-debounce from 10.0.6 to 10.1.1 (#127) Bumps [use-debounce](https://github.com/xnimorz/use-debounce) from 10.0.6 to 10.1.1. - [Release notes](https://github.com/xnimorz/use-debounce/releases) - [Changelog](https://github.com/xnimorz/use-debounce/blob/master/CHANGELOG.md) - [Commits](https://github.com/xnimorz/use-debounce/commits) --- updated-dependencies: - dependency-name: use-debounce dependency-version: 10.1.1 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump hono in the npm_and_yarn group across 1 directory (#104) Bumps the npm_and_yarn group with 1 update in the / directory: [hono](https://github.com/honojs/hono). Updates `hono` from 4.12.9 to 4.12.12 - [Release notes](https://github.com/honojs/hono/releases) - [Commits](https://github.com/honojs/hono/compare/v4.12.9...v4.12.12) --- updated-dependencies: - dependency-name: hono dependency-version: 4.12.12 dependency-type: indirect dependency-group: npm_and_yarn ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump react-hook-form from 7.70.0 to 7.72.1 (#130) Bumps [react-hook-form](https://github.com/react-hook-form/react-hook-form) from 7.70.0 to 7.72.1. - [Release notes](https://github.com/react-hook-form/react-hook-form/releases) - [Changelog](https://github.com/react-hook-form/react-hook-form/blob/master/CHANGELOG.md) - [Commits](https://github.com/react-hook-form/react-hook-form/compare/v7.70.0...v7.72.1) --- updated-dependencies: - dependency-name: react-hook-form dependency-version: 7.72.1 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps-dev): bump @tailwindcss/postcss from 4.1.18 to 4.2.2 (#131) Bumps [@tailwindcss/postcss](https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/@tailwindcss-postcss) from 4.1.18 to 4.2.2. - [Release notes](https://github.com/tailwindlabs/tailwindcss/releases) - [Changelog](https://github.com/tailwindlabs/tailwindcss/blob/main/CHANGELOG.md) - [Commits](https://github.com/tailwindlabs/tailwindcss/commits/v4.2.2/packages/@tailwindcss-postcss) --- updated-dependencies: - dependency-name: "@tailwindcss/postcss" dependency-version: 4.2.2 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps-dev): bump lucide-static from 1.7.0 to 1.8.0 (#123) Bumps [lucide-static](https://github.com/lucide-icons/lucide) from 1.7.0 to 1.8.0. - [Release notes](https://github.com/lucide-icons/lucide/releases) - [Commits](https://github.com/lucide-icons/lucide/compare/1.7.0...1.8.0) --- updated-dependencies: - dependency-name: lucide-static dependency-version: 1.8.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump @tanstack/react-query from 5.96.2 to 5.99.0 (#128) Bumps [@tanstack/react-query](https://github.com/TanStack/query/tree/HEAD/packages/react-query) from 5.96.2 to 5.99.0. - [Release notes](https://github.com/TanStack/query/releases) - [Changelog](https://github.com/TanStack/query/blob/main/packages/react-query/CHANGELOG.md) - [Commits](https://github.com/TanStack/query/commits/@tanstack/react-query@5.99.0/packages/react-query) --- updated-dependencies: - dependency-name: "@tanstack/react-query" dependency-version: 5.99.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps-dev): bump @types/node from 25.5.2 to 25.6.0 (#132) Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 25.5.2 to 25.6.0. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node) --- updated-dependencies: - dependency-name: "@types/node" dependency-version: 25.6.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps-dev): bump @next/eslint-plugin-next from 16.2.2 to 16.2.3 (#134) Bumps [@next/eslint-plugin-next](https://github.com/vercel/next.js/tree/HEAD/packages/eslint-plugin-next) from 16.2.2 to 16.2.3. - [Release notes](https://github.com/vercel/next.js/releases) - [Changelog](https://github.com/vercel/next.js/blob/canary/release.js) - [Commits](https://github.com/vercel/next.js/commits/v16.2.3/packages/eslint-plugin-next) --- updated-dependencies: - dependency-name: "@next/eslint-plugin-next" dependency-version: 16.2.3 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * feat(payment): typed wagmi error handling + onReplaced support (#115) * feat(payment): typed wagmi error handling + onReplaced support Replace fragile string-matching error classification with typed detection via viem's BaseError.walk() across the payment and wallet-connect features. Add onReplaced callback to handle user speedup/cancel of pending transactions. Component A: shared/lib/web3-errors - New module with isUserRejected, isInsufficientFunds, isChainMismatch, isReceiptNotFound, isReceiptTimeout, isTxReverted, walkCause - Walks BaseError cause chain via viem's typed API, falls back to string matching for non-BaseError edge cases (mobile WalletConnect) - 38 unit tests covering direct, wrapped, and fallback paths Component B: classifier refactor - classify-error.ts rewritten to use typed detectors before string matching - Removed step-based NETWORK_SWITCH_FAILED fallback — was masking user rejections of network switches - Added TX_REPLACED to PaymentErrorType + ERROR_MESSAGES entry - CANCELED_COPY constant for message unification - connection-error.ts now calls isUserRejected first for typed detection Component C: payment flow integration - use-payment-flow.ts: console.error moved below USER_REJECTED early return (fixes verbose wagmi stack in console on user cancel) - useWaitForTransactionReceipt now receives onReplaced callback: - reason 'cancelled' → toast + RESET (user intent) - reason 'replaced'/'repriced' → update hash + continue - New REPLACED reducer action for hash swap during confirming state - use-payment-verification.ts: sanitize raw viem errors through formatErrorMessage before writing to store + onReplaced observability * refactor(payment): address review feedback on typed wagmi error handling - Drop unused _step parameter from classifyPaymentError (dead arg after step-based fallback removal); update call site and 20+ test cases. - Fix incorrect comment in usePaymentVerification onReplaced — both hooks consume useWaitForTransactionReceipt in parallel, not sequentially. - Add TransactionExecutionError coverage to detect.test.ts (revert vs OOG shortMessage branches). * feat(payment-panel): persistent network chip across all states Adds a branded NetworkIcon + name chip at the top of PaymentPanel so payers always see which chain the payment targets — visible in pending, paid, paid-fallback and overdue states. Reserves right-side space via pr-12 to avoid overlap with the minimize button. Also migrates AmountDisplay assertions from toBeDefined() to toBeInTheDocument() per testing rules. * refactor(payment-panel): anchor network chip to amount, own minimize button Move the network chip from the panel header into each state's heading row (Total Due / Payment Successful / Expired / paid-fallback) so it sits beside the amount it qualifies — semantically tying chain to value instead of floating in an empty header strip. Extract NetworkChip into a shared presentational component to drop duplication across states. Pull the minimize button into PaymentPanel behind an onMinimize prop, removing the duplicated absolute overlay from PayWorkspace and InvoiceWorkspace. The button now coordinates with the pr-12 right-side clearance baked into every heading row. * fix(history): network icons, button sizing, robust template flow - NetworkBadge: render NetworkIcon (web3icons) before name - InvoiceCard: match Confirm/Cancel button height to regular buttons (min-h-[44px] py-2.5) to prevent layout shift on delete toggle - InvoiceList: replace fragile duplicateFromUrl + setState + push flow with hash-based navigation /create?template=1#<hash> - CreateWorkspace: detect ?template=1 and reset issuedAt/dueAt/total/ magicDust after replaceDraft so templates start with fresh dates - Remove unused duplicate-invoice.ts and its test mock * refactor(payment-panel): group network chip with due/paid date Relocates NetworkChip into a compact metadata row next to the due date (pending) or relative paidAt (paid/expired). Drops the "TOTAL DUE" label — the amount is self-explanatory and the label created a "Total Due ... Due May 2" tautology with the date chunk. - pending: [chip] Due <date> above the amount - paid: [chip] Funds sent · <relative> under Payment Successful - expired: [chip] Was due <date> · Payment disabled under header Adds formatRelativeTime() in shared/lib/date-time for ISO → "Just now" / "5 min ago" / "2 h ago" rendering. PaymentPanel now subscribes to tracked paidAt via a store selector so the subtitle reactively updates when the payment transitions to paid. Clears the chip out of the emerald amount accent box on paid state — zinc chip no longer clashes with the emerald tint. * fix(wallet): visible loading state during wagmi reconnect SmartPayButton and WalletButton both appeared frozen while wagmi restored the persisted connection: the pay button stayed on "Pay X Y" while disabled, and the header wallet button was hidden via opacity:0 so clicks fell through. Now both surfaces render an explicit disabled "Reconnecting…" state with a visible spinner and aria-busy. Covered by 6 new tests (3 SmartPayButton reconnect cases, 3 WalletButton). * fix(wallet): cover SSR pre-hydration gap in pay + header buttons Two bugs under one symptom ("click during page-load race gets stuck at Connecting"): 1. Pre-hydration gap: wagmi with `ssr: true` reports `status: 'disconnected'` on the first client render even when a persisted connection exists in localStorage. `isReconnecting` is false in that window, so the previous fix did not catch it — SmartPayButton flashed a clickable "Connect Wallet" and WalletButton did the same in the header. 2. Stuck-at-connecting race: when a user clicked through the flash, `handlePay` entered `connecting` and opened the Rainbow modal. Meanwhile wagmi finished the background reconnect. The lifecycle effect in `usePaymentFlow` checked `connectModalOpen` before `isConnected`, so if Rainbow's modal state didn't cleanly flip through the expected order the flow stayed in `connecting` forever. Fix: - New shared hook `useWagmiHydrating` detects pre-hydration (persisted connector id in localStorage + wagmi still on initial disconnected), plus the normal `connecting` / `reconnecting` statuses. Drops the pre-hydration heuristic once wagmi leaves the initial snapshot so later manual disconnect/reconnect cycles behave normally. - SmartPayButton and WalletButton now use `useWagmiHydrating` instead of `isReconnecting`. Both render a disabled loading button with aria-busy=true across the whole hydration window. - `usePaymentFlow` connecting effect now checks `isConnected` before `connectModalOpen`, so a background reconnect always wins and the flow cannot strand in `connecting`. - Regression tests: reorder-safe race in `use-payment-flow`, pre-hydration coverage in SmartPayButton + WalletButton suites. 387 payment + wallet-connect tests green. * fix(payment): cap wait-for-receipt timeout at 60s, disable retry Ensures a stuck transaction surfaces a user-visible RPC_ERROR banner within one block window instead of hanging on the spinner. Previously, viem's 180s default timeout combined with TanStack Query's default retry (3) meant the first user-visible error could be delayed by up to 9 minutes. Also drops the TEMP DEBUG console.logs added during manual test verification — all three test paths (USER_REJECTED silence, onReplaced cancel, onReplaced speedup) have been validated on Eth Sepolia + Rabby. Part of PR #115. * fix(payment): raise wait-for-receipt timeout to viem default 180s 60s was too aggressive — near-zero-gas transactions legitimately need several blocks on L1 before inclusion. Combined with retry: 0 this still caps the hidden wait at 3 minutes (vs viem's default retry × 180s = 9 minutes that motivated the original fix). Field-verified on Base Sepolia: a stuck tx now surfaces the RPC_ERROR banner as expected — only thing that needed tuning was the ceiling. Part of PR #115. * fix(payment-panel): make error banner X button clickable and cursor visible Tailwind v4 dropped the default pointer cursor on <button>, and dismissError only cleared the store — local paymentError stayed set, so the X appeared dead. Add cursor-pointer + type=button, and wire a composite handler that clears both paymentError and the tracked-invoice store error. * refactor(payment): simplify PR #115 after parallel review Findings from three parallel review agents (reuse, quality, efficiency) aggregated and fixed: - Remove dead TX_REPLACED PaymentErrorType: defined but never emitted (onReplaced dispatches REPLACED/RESET directly, classifier never returns it) - Remove walkCause from web3-errors barrel export: internal-only, test file imports from ../detect - Memoize onReplaced + extract RECEIPT_QUERY_OPTIONS/TIMEOUT_MS to module level in use-payment-flow.ts (inline refs were re-subscribing TanStack Query / viem watcher every render during confirming step) - Hoist stateless handleVerificationReplaced + memoize receiptQuery in use-payment-verification.ts (compounded by useBlockNumber watch: true) - Unwrap naked <div> wrapper with no props/layout in WalletButton.tsx - Fix misleading CANCELED_COPY comment (claimed cross-feature usage that never existed) Follow-ups tracked in #120 (NetworkChip/NetworkBadge unification), #121 (nowUnix migration). Net: -71 / +66 lines. Type-check, lint, 277 affected tests pass. * fix(payment): address PR #115 review findings - use receipt.transactionHash on CONFIRMED so replaced/repriced tx hashes aren't overwritten by the stale wagmi send hash - REPLACED reducer explicitly clears error for future-proofing - console.error logs shortMessage only to avoid leaking calldata if observability is wired later - use-payment-verification: consolidate imports above function decl - add reducer test covering REPLACED error preservation * fix(payment): correct block-time drift breaking creator-side verification Root cause: AVG_BLOCK_TIME_MS[11155111] was 12_000 but Sepolia actually runs ~13s/block. Over 35 days of forward drift estimateFromBlockHex returned a block above the real chain head; alchemy_getAssetTransfers returned empty and creators saw "payment not found" on confirmed transactions. Arbitrum Sepolia had the same class of bug (250ms assumed vs ~286ms measured). - AVG_BLOCK_TIME_MS: Sepolia 12000→13000, Arb Sepolia 250→286 (measured via 10k-block samples across all 10 supported chains). REFERENCE_BLOCKS left frozen — v1.0 shipped Mar 28, old invoices must decode with the same calibration they were created with. - /api/transfers: defense-in-depth safety net. Fetches eth_blockNumber in parallel with the transfers query, and on drifted client fromBlock retries with a 3-day lookback anchored to the real chain head. Drift logged via console.warn for observability. Eliminates the bug class regardless of anchor staleness. - scripts/measure-block-times.ts + pnpm check:block-drift: diagnostic that measures real avgBlockTime for every chain, compares vs hardcoded values, reports lookback margin, and exits non-zero on BROKEN verdict. - Route tests updated for the new parallel fetch; added cases covering both retry and no-retry paths of the s…
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR implements the Binary V3 codec for invoice URL compression and refactors the invoice schema for better readability.
Binary Codec V3
Invoice Schema Refactoring
v→version,id→invoiceId,iss→issuedAt,due→dueAtnet→networkId,cur→currency,t→tokenAddressf→from,c→client,it→itemstaxIdfield for counterpartiesCreatorStore Migration
InvoiceDraft, useDraftState(meta +Partial<Invoice>)LineItem[]for React key managementrecipient→client,sender→from,chainId→networkIdCleanup
Files Changed
50 files changed, +2608 / -897 lines
Breaking Changes
Test plan
pnpm type-checkpassespnpm lintpassespnpm testpasses🤖 Generated with Claude Code