📚 Enhance project setup & maintenance workflows

- 📝 Add comprehensive README.md, CONTRIBUTING.md, and 🔒 SECURITY.md documentation
- 🔧 Integrate code formatting tool and refactor existing codebase to meet style guidelines
- ⬆️ Update project dependencies to latest stable versions
- 🤖 Implement pre-commit hook for automated code formatting

#documentation #tooling #maintenance
This commit is contained in:
Danny Morabito 2025-03-10 17:14:09 +01:00
parent 25b3972f8b
commit 18e4ad7629
Signed by: dannym
GPG key ID: 7CC8056A5A04557E
47 changed files with 1027 additions and 568 deletions

4
.gitignore vendored
View file

@ -6,8 +6,8 @@ node_modules
dist dist
out out
extras extras
# we are using bun, the package-json only exists after running the macos build # we are using bun, the package-lock.json only exists after running the macos build
package-json.lock package-lock.json
# Editor directories and files # Editor directories and files
.vscode/* .vscode/*

4
.hooks/pre-commit Executable file
View file

@ -0,0 +1,4 @@
#!/usr/bin/env bash
bun install
bun run lint:fix

158
Contributing.md Normal file
View file

@ -0,0 +1,158 @@
# Contributing to EVE
Thank you for your interest in contributing to EVE! We're excited to have you join our mission to build a truly sovereign community platform. This document provides guidelines and information to help make your contribution process smooth and effective.
## Getting Started
### Prerequisites
- Bun v1.2.0 or higher
- Git
### Setting Up Your Development Environment
1. Fork the repository
2. Clone the fork repository:
```bash
git clone [forked repository URL]
git remote add upstream https://git.arx-ccn.com/Arx/Eve.git
cd Eve
```
3. Install dependencies:
```bash
bun install
```
4. Start the development server:
```bash
bun run dev
```
## Development Workflow
1. **Choose an issue**: Start by looking at open issues in our [issue tracker](https://git.arx-ccn.com/Arx/Eve/issues). Comment on the issue to indicate you're working on it to avoid duplicate efforts.
2. **Create a branch**: Create a new branch for your work:
```bash
git checkout -b feature/your-feature-name
```
3. **Make your changes**: Implement your feature or fix.
4. **Format your code**: Before committing, ensure your code follows our formatting standards:
```bash
bunx biome format --write src/
```
5. **Commit your changes**: Write clear, concise commit messages:
```bash
git commit -m "Add feature: brief description of what you did"
```
## Code Style Guidelines
We use Biome for code formatting to maintain consistent style across the codebase. Running the format command before committing ensures your code adheres to our standards:
```bash
bun run lint:fix
```
## Testing
When implementing new features or fixing bugs, please include appropriate tests. Run the test suite to ensure your changes don't break existing functionality:
```bash
bun test
```
## Pull Request Process
1. **Push your changes** to your fork.
2. **Create a Pull Request** to the main EVE repository.
3. **Describe your changes** in the PR description:
- What does this PR do?
- Why is it needed?
- How has it been tested?
4. **Address review feedback**: Be responsive to comments and be willing to make changes if requested.
## Project Structure
The project uses the following technologies:
- Nostr
- TypeScript
- Electron
- Lit
## Building
For development:
```bash
bun run dev
```
For production you will need to have the relay repo cloned on ../Relay, then simply run:
```bash
./build.sh
```
## Ways to Contribute
There are many ways to contribute to EVE beyond writing code:
### Design
We welcome contributions to improve the user interface and experience:
- UI mockups and prototypes
- Icon designs
- Accessibility improvements
- User flow diagrams
### Documentation
Help improve our documentation:
- User guides
- API documentation
- Tutorial content
- Example use cases
### Testing and QA
- Report bugs
- Write test cases
- Perform usability testing
- Suggest improvements
### Community Support
- Answer questions from other users
- Help triage issues
- Write blog posts or tutorials about EVE
## License and Legal
EVE is licensed under the [GNU Affero General Public License v3.0 (AGPL-3.0)](https://www.gnu.org/licenses/agpl-3.0.en.html). By contributing to EVE, you agree that your contributions will be licensed under the same license.
We do not require a separate Contributor License Agreement (CLA).
## Recognition
All contributors will be recognized in our CONTRIBUTORS.md file. We value every contribution, no matter how small!
---
Remember that EVE is in alpha stage, and many components are still evolving. Your contributions are helping to build a more sovereign digital future!

117
Readme.md
View file

@ -1 +1,116 @@
# Eve # EVE: The Sovereign Community Platform
<p align="center">
<img src="public/icon512x512.png" alt="Eve Logo" width="200" />
<br>
<em>Reclaim your digital garden. No serpents allowed.</em>
</p>
---
> ⚠️ ALPHA STAGE DISCLAIMER: EVE is currently in early alpha development. Many features described here are still in development or planned for future releases. The platform is rapidly evolving, and you may encounter bugs, incomplete functionality, or significant changes between versions. We welcome early adopters and contributors who share our vision, but please be aware of the platform's developmental status.
## What is EVE?
**EVE** is an open-source platform that enables **self-sovereign communities** to connect, collaborate, and govern themselves without centralized control. Built on principles of privacy, decentralization, and user autonomy, EVE provides the tools for digital independence in an increasingly monitored online world.
## Core Principles
| Principle | Description |
| :----------------- | :----------------------------------------------------------------------------------------------------------------------------- |
| **Friction-less** | Technology that serves you without dark patterns or engagement tricks. Works consistently as an extension of human connection. |
| **Self-governed** | Communities set their own rules through consensus and reputation systems, not through platform dictates. |
| **Decentralized** | Operates across a peer-to-peer network with no central servers or single points of failure. |
| **Private** | End-to-end encryption by default. Your data remains under your control. |
| **Uncensorable** | Communities set their own standards for expression and communication. |
| **Resilient** | The network continues even if we don't. Open protocol, free code, distributed architecture. |
| **Self-sovereign** | Your identity and reputation belong to you, not borrowed from other platforms. |
| **Trust-based** | Communities grow through human vouching rather than algorithmic recommendations. |
## Technical Foundation
- **Local-first architecture**: All community data is stored locally on your device first
- **Encrypted sharing**: Data is shared with community members using the secure [MLS (Messaging Layer Security)](https://messaginglayersecurity.rocks/mls-architecture/draft-ietf-mls-architecture.html) protocol
- **Nostr protocol**: Uses [Nostr](https://github.com/nostr-protocol/nips) as the communication layer to relay encrypted data between users
- **Peer-to-peer synchronization**: Direct encrypted connections between members without central servers
- **Zero-knowledge design**: Even the platform developers cannot access your community data
Check out the [Relay repo](https://git.arx-ccn.com/Arx/Eve-Relay) for MLS implementation details
## How It Works
1. Your data is stored locally on your device
2. When sharing with community members, data is encrypted using MLS
3. The encrypted data is transmitted via the Nostr protocol
4. Only authorized community members with proper keys can decrypt and access the shared content
5. This ensures privacy and security while maintaining decentralization
## Modular Ecosystem
EVE provides building blocks for digital sovereignty, which we call Arxlets:
### Core Modules
- [x] **Phora**: Threaded discussions and knowledge sharing
- [ ] **Nexus**: Central community hub
- [ ] **Whisper**: One-to-one and group messaging
- [ ] **Vault**: Secure file storage and sharing
- [ ] **Assembly**: Governance and voting systems
- [ ] **Treasury**: Resource management with Bitcoin integration
- [ ] **Agora**: Peer-to-peer marketplaces
- [ ] **Beacon**: Event coordination and calendaring
- [ ] **Codex**: Collaborative documents and wikis
- [ ] **Forge**: Project and task management
- [ ] **Loom**: Workflow automation and integrations
## The Trust Protocol
EVE's reputation system creates accountability through cryptographic trust bonds between members:
- When you invite someone, your reputations become linked
- **Positive contributions** benefit both parties (with diminishing returns for inviters)
- **Negative actions** penalize both parties (with amplified consequences for inviters)
- This creates natural incentives for careful vouching and community quality
Communities can customize these parameters to match their specific governance needs.
## Getting Started
```bash
git clone https://git.arx-ccn.com/Arx/Eve
cd Eve
bun install
bun run dev
```
### Requirements
- Bun v1.2.0 or higher
```bash
curl -fsSL https://bun.sh/install | bash
```
## Contributing
Please read our [Contributing Guide](Contributing.md) for instructions on how to contribute to EVE.
## Security
Please read our [Security Policy](Security.md) for information on how to report security vulnerabilities in EVE.
## License
EVE is released under the [GNU Affero General Public License v3.0](https://choosealicense.com/licenses/agpl-3.0/), which guarantees that it will:
- **Remain open-source** — The code will always be accessible and modifiable
- **Stay free** — No one can ever charge for access to the core platform
- **Resist capture** — Any modifications must be shared with the community
- **Protect user freedom** — Your right to control your digital life is legally protected
---
<p align="center">
<strong>The future belongs to the sovereign.</strong><br>
<em>Join us in building digital freedom.</em>
</p>

92
Security.md Normal file
View file

@ -0,0 +1,92 @@
# SECURITY
## Security Policy for EVE
We take security seriously. We appreciate the community's efforts in identifying and responsibly disclosing potential security vulnerabilities.
## Reporting a Vulnerability
If you believe you've found a security vulnerability in EVE, please report it to us privately using one of these methods:
### Option 1: Encrypted Nostr DM
Send a NIP-44 encrypted direct message to:
```
npub1ven4zk8xxw873876gx8y9g9l9fazkye9qnwnglcptgvfwxmygscqsxddfh
```
### Option 2: Email with PGP Encryption
Send an encrypted email to `danny@arx-ccn.com` using the following PGP key:
```
-----BEGIN PGP PUBLIC KEY BLOCK-----
xjMEZVPfuBYJKwYBBAHaRw8BAQdA4zXdIpn1sxtUekC5KNUZB4ooaTTdE+7WfIL6
m3DV/dzNIkRhbm55IE1vcmFiaXRvIDxkYW5ueUBhcngtY2NuLmNvbT7CjwQTFggA
NxYhBPl51bOOAki9ZNroKXzIBWpaBFV+BQJlU9+4BQkFo5qAAhsDBAsJCAcFFQgJ
CgsFFgIDAQAACgkQfMgFaloEVX5prgEAtIckL9dtUrqBvkMD3b/qJLiDtEK1u9iU
/1LlDexi0hABAK3uKIVyPqxJKQ5jOAFb0bta9QexBsfTbzZLSbrZR4UDzjgEZVPf
uBIKKwYBBAGXVQEFAQEHQNFXMjAbVS5dQQ17EHM39VvvF3HKeqBoq0peKIYSpjs3
AwEIB8J+BBgWCAAmFiEE+XnVs44CSL1k2ugpfMgFaloEVX4FAmVT37gFCQWjmoAC
GwwACgkQfMgFaloEVX7VIAEA0pT6Ih7XTym0VNEndQw8Fytfn97JT13N+S9CumpO
qQEBALEPtcimm4t7RZDlZCk0I/V/4eLnPf94w8MCDOKae3wG
=K8X3
-----END PGP PUBLIC KEY BLOCK-----
```
## What to Include in Your Report
Please include the following information in your vulnerability report:
1. Description of the vulnerability
2. Steps to reproduce
3. Potential impact
4. Any suggested mitigations (if applicable)
5. Whether you'd like to be credited for the discovery
## Vulnerability Severity Classification
We classify vulnerabilities according to the following severity levels:
| Severity | Description |
| ------------ | ---------------------------------------------------------------------------------------------------------------------- |
| **Critical** | Vulnerabilities that can lead to system compromise, unauthorized access to CCN data, or significant service disruption |
| **High** | Vulnerabilities that can lead to partial service disruption |
| **Medium** | Vulnerabilities that may expose non-sensitive information or affect functionality in a limited way |
| **Low** | Minor issues with minimal security impact |
Please include your assessment of the severity in your report.
## Responsible Disclosure Policy
- We will acknowledge receipt of your vulnerability report within 72 hours.
- We will provide an initial assessment of the report within 7 days.
- We will work diligently to verify and address the reported issue, prioritizing based on severity.
- We request that you do not publicly disclose the vulnerability until we've had adequate time to address it.
- After 60 days from acknowledgment, if we haven't addressed the issue, you may disclose it publicly.
## Scope
This security policy applies to the following official EVE repositories and components:
- Main EVE application: https://git.arx-ccn.com/Arx/Eve
- EVE Relay: https://git.arx-ccn.com/Arx/Eve-Relay
- All published Arxlets (Phora, Nexus, etc.)
### Out of Scope
- Third-party integrations not maintained by the Arx team
- Community forks not officially supported by the Arx team
- Issues already publicly disclosed or previously reported
## Security Updates
Security updates will be released as soon as possible after verification and remediation, with priority given to Critical and High severity issues. We will provide information about the vulnerability and the fix in release notes.
## Recognition
We believe in recognizing the valuable contributions of security researchers. With your permission, we will acknowledge your contribution in our release notes and CONTRIBUTORS.md file.
Thank you for helping keep EVE and its users secure!

39
biome.json Normal file
View file

@ -0,0 +1,39 @@
{
"$schema": "./node_modules/@biomejs/biome/configuration_schema.json",
"files": {
"include": ["src/**/*.ts"]
},
"linter": {
"enabled": true,
"rules": {
"style": {
"noNonNullAssertion": "off",
"useNodejsImportProtocol": "warn"
},
"complexity": {
"useLiteralKeys": "off"
}
}
},
"formatter": {
"enabled": true,
"formatWithErrors": true,
"ignore": [],
"attributePosition": "auto",
"indentStyle": "space",
"indentWidth": 2,
"lineWidth": 120,
"lineEnding": "lf"
},
"javascript": {
"formatter": {
"arrowParentheses": "always",
"bracketSameLine": true,
"bracketSpacing": true,
"quoteStyle": "single",
"quoteProperties": "asNeeded",
"semicolons": "always",
"trailingCommas": "all"
}
}
}

View file

@ -1,5 +1,5 @@
#!/bin/zsh #!/bin/zsh
set -e # Exit on any error set -e # Exit on any error
log() { log() {
echo "🔨 $1" echo "🔨 $1"
@ -37,7 +37,7 @@ docker run --rm -it \
-v "${HOME}/.ssh:/root/.ssh" \ -v "${HOME}/.ssh:/root/.ssh" \
-v /var/run/docker.sock:/var/run/docker.sock \ -v /var/run/docker.sock:/var/run/docker.sock \
electronuserland/builder \ electronuserland/builder \
/bin/bash -c "npm install && npm run build:mac" || error "macOS build failed" /bin/bash -c "npm install --ignore-scripts && npm run build:mac" || error "macOS build failed"
# Output paths # Output paths
VERSION=$(node -p "require('./package.json').version") VERSION=$(node -p "require('./package.json').version")

179
bun.lock
View file

@ -6,30 +6,27 @@
"dependencies": { "dependencies": {
"@lit-labs/motion": "^1.0.8", "@lit-labs/motion": "^1.0.8",
"@noble/ciphers": "^1.2.1", "@noble/ciphers": "^1.2.1",
"@nostr-dev-kit/ndk": "^2.10.7", "@nostr-dev-kit/ndk": "^2.12.2",
"@nostr/tools": "npm:@jsr/nostr__tools", "@nostr/tools": "npm:@jsr/nostr__tools",
"@open-wc/lit-helpers": "^0.7.0", "@open-wc/lit-helpers": "^0.7.0",
"@std/encoding": "npm:@jsr/std__encoding", "@std/encoding": "npm:@jsr/std__encoding",
"iconify-icon": "^2.2.0",
"lit": "^3.2.1", "lit": "^3.2.1",
"markdown-it": "^14.1.0", "markdown-it": "^14.1.0",
}, },
"devDependencies": { "devDependencies": {
"@biomejs/biome": "^1.9.4",
"@electron-toolkit/preload": "^3.0.1", "@electron-toolkit/preload": "^3.0.1",
"@electron-toolkit/utils": "^4.0.0", "@electron-toolkit/utils": "^4.0.0",
"@tsconfig/node22": "^22.0.0", "@tsconfig/node22": "^22.0.0",
"@types/markdown-it": "^14.1.2", "@types/markdown-it": "^14.1.2",
"@types/node": "^22.10.2", "@types/node": "^22.13.10",
"electron": "^34.2.0", "electron": "^34.3.2",
"electron-builder": "^25.1.8", "electron-builder": "^25.1.8",
"electron-vite": "^3.0.0", "electron-vite": "^3.0.0",
"lightningcss": "^1.28.2", "lightningcss": "^1.29.2",
"sass-embedded": "^1.83.0", "sass-embedded": "^1.85.1",
"typescript": "~5.6.3", "typescript": "~5.6.3",
"vite": "^6.0.5", "vite": "^6.2.1",
},
"optionalDependencies": {
"dmg-license": "^1.0.11",
}, },
}, },
}, },
@ -72,6 +69,24 @@
"@babel/types": ["@babel/types@7.26.9", "", { "dependencies": { "@babel/helper-string-parser": "^7.25.9", "@babel/helper-validator-identifier": "^7.25.9" } }, "sha512-Y3IR1cRnOxOCDvMmNiym7XpXQ93iGDDPHx+Zj+NM+rg0fBaShfQLkg+hKPaZCEvg5N/LeCo4+Rj/i3FuJsIQaw=="], "@babel/types": ["@babel/types@7.26.9", "", { "dependencies": { "@babel/helper-string-parser": "^7.25.9", "@babel/helper-validator-identifier": "^7.25.9" } }, "sha512-Y3IR1cRnOxOCDvMmNiym7XpXQ93iGDDPHx+Zj+NM+rg0fBaShfQLkg+hKPaZCEvg5N/LeCo4+Rj/i3FuJsIQaw=="],
"@biomejs/biome": ["@biomejs/biome@1.9.4", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "1.9.4", "@biomejs/cli-darwin-x64": "1.9.4", "@biomejs/cli-linux-arm64": "1.9.4", "@biomejs/cli-linux-arm64-musl": "1.9.4", "@biomejs/cli-linux-x64": "1.9.4", "@biomejs/cli-linux-x64-musl": "1.9.4", "@biomejs/cli-win32-arm64": "1.9.4", "@biomejs/cli-win32-x64": "1.9.4" }, "bin": { "biome": "bin/biome" } }, "sha512-1rkd7G70+o9KkTn5KLmDYXihGoTaIGO9PIIN2ZB7UJxFrWw04CZHPYiMRjYsaDvVV7hP1dYNRLxSANLaBFGpog=="],
"@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@1.9.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-bFBsPWrNvkdKrNCYeAp+xo2HecOGPAy9WyNyB/jKnnedgzl4W4Hb9ZMzYNbf8dMCGmUdSavlYHiR01QaYR58cw=="],
"@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@1.9.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-ngYBh/+bEedqkSevPVhLP4QfVPCpb+4BBe2p7Xs32dBgs7rh9nY2AIYUL6BgLw1JVXV8GlpKmb/hNiuIxfPfZg=="],
"@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@1.9.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-fJIW0+LYujdjUgJJuwesP4EjIBl/N/TcOX3IvIHJQNsAqvV2CHIogsmA94BPG6jZATS4Hi+xv4SkBBQSt1N4/g=="],
"@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@1.9.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-v665Ct9WCRjGa8+kTr0CzApU0+XXtRgwmzIf1SeKSGAv+2scAlW6JR5PMFo6FzqqZ64Po79cKODKf3/AAmECqA=="],
"@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@1.9.4", "", { "os": "linux", "cpu": "x64" }, "sha512-lRCJv/Vi3Vlwmbd6K+oQ0KhLHMAysN8lXoCI7XeHlxaajk06u7G+UsFSO01NAs5iYuWKmVZjmiOzJ0OJmGsMwg=="],
"@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@1.9.4", "", { "os": "linux", "cpu": "x64" }, "sha512-gEhi/jSBhZ2m6wjV530Yy8+fNqG8PAinM3oV7CyO+6c3CEh16Eizm21uHVsyVBEB6RIM8JHIl6AGYCv6Q6Q9Tg=="],
"@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@1.9.4", "", { "os": "win32", "cpu": "arm64" }, "sha512-tlbhLk+WXZmgwoIKwHIHEBZUwxml7bRJgk0X2sPyNR3S93cdRq6XulAZRQJ17FYGGzWne0fgrXBKpl7l4M87Hg=="],
"@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@1.9.4", "", { "os": "win32", "cpu": "x64" }, "sha512-8Y5wMhVIPaWe6jw2H+KlEm4wP/f7EW3810ZLmDlrEEy5KvBsb9ECEfu/kMWD484ijfQ8+nIi0giMgu9g1UAuuA=="],
"@bufbuild/protobuf": ["@bufbuild/protobuf@2.2.3", "", {}, "sha512-tFQoXHJdkEOSwj5tRIZSPNUuXK3RaR7T1nUrPgbYX1pUbvqqaaZAsfo+NXBPsz5rZMSKVFrgK1WL8Q/MSLvprg=="], "@bufbuild/protobuf": ["@bufbuild/protobuf@2.2.3", "", {}, "sha512-tFQoXHJdkEOSwj5tRIZSPNUuXK3RaR7T1nUrPgbYX1pUbvqqaaZAsfo+NXBPsz5rZMSKVFrgK1WL8Q/MSLvprg=="],
"@develar/schema-utils": ["@develar/schema-utils@2.6.5", "", { "dependencies": { "ajv": "^6.12.0", "ajv-keywords": "^3.4.1" } }, "sha512-0cp4PsWQ/9avqTVMCtZ+GirikIA36ikvjtHweU4/j8yLtgObI0+JUPhYFScgwlteveGB1rt3Cm8UhN04XayDig=="], "@develar/schema-utils": ["@develar/schema-utils@2.6.5", "", { "dependencies": { "ajv": "^6.12.0", "ajv-keywords": "^3.4.1" } }, "sha512-0cp4PsWQ/9avqTVMCtZ+GirikIA36ikvjtHweU4/j8yLtgObI0+JUPhYFScgwlteveGB1rt3Cm8UhN04XayDig=="],
@ -144,8 +159,6 @@
"@gar/promisify": ["@gar/promisify@1.1.3", "", {}, "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw=="], "@gar/promisify": ["@gar/promisify@1.1.3", "", {}, "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw=="],
"@iconify/types": ["@iconify/types@2.0.0", "", {}, "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg=="],
"@isaacs/cliui": ["@isaacs/cliui@8.0.2", "", { "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", "strip-ansi": "^7.0.1", "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", "wrap-ansi": "^8.1.0", "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" } }, "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA=="], "@isaacs/cliui": ["@isaacs/cliui@8.0.2", "", { "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", "strip-ansi": "^7.0.1", "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", "wrap-ansi": "^8.1.0", "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" } }, "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA=="],
"@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.8", "", { "dependencies": { "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA=="], "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.8", "", { "dependencies": { "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA=="],
@ -176,7 +189,7 @@
"@noble/secp256k1": ["@noble/secp256k1@2.2.3", "", {}, "sha512-l7r5oEQym9Us7EAigzg30/PQAvynhMt2uoYtT3t26eGDVm9Yii5mZ5jWSWmZ/oSIR2Et0xfc6DXrG0bZ787V3w=="], "@noble/secp256k1": ["@noble/secp256k1@2.2.3", "", {}, "sha512-l7r5oEQym9Us7EAigzg30/PQAvynhMt2uoYtT3t26eGDVm9Yii5mZ5jWSWmZ/oSIR2Et0xfc6DXrG0bZ787V3w=="],
"@nostr-dev-kit/ndk": ["@nostr-dev-kit/ndk@2.12.0", "", { "dependencies": { "@noble/curves": "^1.6.0", "@noble/hashes": "^1.5.0", "@noble/secp256k1": "^2.1.0", "@scure/base": "^1.1.9", "debug": "^4.3.6", "light-bolt11-decoder": "^3.2.0", "nostr-tools": "^2.7.1", "tseep": "^1.2.2", "typescript-lru-cache": "^2.0.0", "utf8-buffer": "^1.0.0", "websocket-polyfill": "^0.0.3" } }, "sha512-B9NKdgn9CKNn0WHIFzj7SxeZhr+daT5im/ozj9Ey791MkaZiTB5XUCy5j9O15FDHTyFy0/gpCyq7LvJKIxCOoA=="], "@nostr-dev-kit/ndk": ["@nostr-dev-kit/ndk@2.12.2", "", { "dependencies": { "@noble/curves": "^1.6.0", "@noble/hashes": "^1.5.0", "@noble/secp256k1": "^2.1.0", "@scure/base": "^1.1.9", "debug": "^4.3.6", "light-bolt11-decoder": "^3.2.0", "nostr-tools": "^2.7.1", "tseep": "^1.2.2", "typescript-lru-cache": "^2.0.0", "utf8-buffer": "^1.0.0", "websocket-polyfill": "^0.0.3" } }, "sha512-uvautgwbpk3AgddoFpew67/FiaV/zpKwwvSnjCvbE/tAdJBpUUS+VjWR5WfUnJvxTy/ZZpPW+X2TkwVFHhUdvA=="],
"@nostr/tools": ["@jsr/nostr__tools@2.10.4", "https://npm.jsr.io/~/11/@jsr/nostr__tools/2.10.4.tgz", { "dependencies": { "@noble/ciphers": "^0.5.1", "@noble/curves": "1.2.0", "@noble/hashes": "1.3.1", "@scure/base": "1.1.1", "@scure/bip32": "1.3.1", "@scure/bip39": "1.2.1", "nostr-wasm": "0.1.0" } }, "sha512-vjgefYXVtr6+m+VEBRc1fxnYoL8iVYOSETsWUQNjLn8BA2v8kgQxEvMHHXMLl9cq4/vZXwGpG352rQoF7KqKxw=="], "@nostr/tools": ["@jsr/nostr__tools@2.10.4", "https://npm.jsr.io/~/11/@jsr/nostr__tools/2.10.4.tgz", { "dependencies": { "@noble/ciphers": "^0.5.1", "@noble/curves": "1.2.0", "@noble/hashes": "1.3.1", "@scure/base": "1.1.1", "@scure/bip32": "1.3.1", "@scure/bip39": "1.2.1", "nostr-wasm": "0.1.0" } }, "sha512-vjgefYXVtr6+m+VEBRc1fxnYoL8iVYOSETsWUQNjLn8BA2v8kgQxEvMHHXMLl9cq4/vZXwGpG352rQoF7KqKxw=="],
@ -262,7 +275,7 @@
"@types/ms": ["@types/ms@2.1.0", "", {}, "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA=="], "@types/ms": ["@types/ms@2.1.0", "", {}, "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA=="],
"@types/node": ["@types/node@22.13.5", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-+lTU0PxZXn0Dr1NBtC7Y8cR21AJr87dLLU953CWA6pMxxv/UDc7jYAY90upcrie1nRcD6XNG5HOYEDtgW5TxAg=="], "@types/node": ["@types/node@22.13.10", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-I6LPUvlRH+O6VRUqYOcMudhaIdUVWfsjnZavnsraHvpBwaEyMN29ry+0UVJhImYL16xsscu0aske3yA+uPOWfw=="],
"@types/plist": ["@types/plist@3.0.5", "", { "dependencies": { "@types/node": "*", "xmlbuilder": ">=11.0.1" } }, "sha512-E6OCaRmAe4WDmWNsL/9RMqdkkzDCY1etutkflWk4c+AcjDU07Pcz1fQwTX0TQz+Pxqn9i4L1TU3UFpjnrcDgxA=="], "@types/plist": ["@types/plist@3.0.5", "", { "dependencies": { "@types/node": "*", "xmlbuilder": ">=11.0.1" } }, "sha512-E6OCaRmAe4WDmWNsL/9RMqdkkzDCY1etutkflWk4c+AcjDU07Pcz1fQwTX0TQz+Pxqn9i4L1TU3UFpjnrcDgxA=="],
@ -434,7 +447,7 @@
"delegates": ["delegates@1.0.0", "", {}, "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ=="], "delegates": ["delegates@1.0.0", "", {}, "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ=="],
"detect-libc": ["detect-libc@1.0.3", "", { "bin": { "detect-libc": "./bin/detect-libc.js" } }, "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg=="], "detect-libc": ["detect-libc@2.0.3", "", {}, "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw=="],
"detect-node": ["detect-node@2.1.0", "", {}, "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g=="], "detect-node": ["detect-node@2.1.0", "", {}, "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g=="],
@ -454,7 +467,7 @@
"ejs": ["ejs@3.1.10", "", { "dependencies": { "jake": "^10.8.5" }, "bin": { "ejs": "bin/cli.js" } }, "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA=="], "ejs": ["ejs@3.1.10", "", { "dependencies": { "jake": "^10.8.5" }, "bin": { "ejs": "bin/cli.js" } }, "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA=="],
"electron": ["electron@34.2.0", "", { "dependencies": { "@electron/get": "^2.0.0", "@types/node": "^20.9.0", "extract-zip": "^2.0.1" }, "bin": { "electron": "cli.js" } }, "sha512-SYwBJNeXBTm1q/ErybQMUBZAYqEreBUqBwTrNkw1rV4YatDZk5Aittpcus3PPeC4UoI/tqmJ946uG8AKHTd6CA=="], "electron": ["electron@34.3.2", "", { "dependencies": { "@electron/get": "^2.0.0", "@types/node": "^20.9.0", "extract-zip": "^2.0.1" }, "bin": { "electron": "cli.js" } }, "sha512-n9tzmFexVLxipZXwMTY30H10f0X9k2OP0SkpSwL5VvnDZi0l/Hc+8CEArKkQPbbSf/IS7nxgc96gtTaR+XoSBg=="],
"electron-builder": ["electron-builder@25.1.8", "", { "dependencies": { "app-builder-lib": "25.1.8", "builder-util": "25.1.7", "builder-util-runtime": "9.2.10", "chalk": "^4.1.2", "dmg-builder": "25.1.8", "fs-extra": "^10.1.0", "is-ci": "^3.0.0", "lazy-val": "^1.0.5", "simple-update-notifier": "2.0.0", "yargs": "^17.6.2" }, "bin": { "electron-builder": "cli.js", "install-app-deps": "install-app-deps.js" } }, "sha512-poRgAtUHHOnlzZnc9PK4nzG53xh74wj2Jy7jkTrqZ0MWPoHGh1M2+C//hGeYdA+4K8w4yiVCNYoLXF7ySj2Wig=="], "electron-builder": ["electron-builder@25.1.8", "", { "dependencies": { "app-builder-lib": "25.1.8", "builder-util": "25.1.7", "builder-util-runtime": "9.2.10", "chalk": "^4.1.2", "dmg-builder": "25.1.8", "fs-extra": "^10.1.0", "is-ci": "^3.0.0", "lazy-val": "^1.0.5", "simple-update-notifier": "2.0.0", "yargs": "^17.6.2" }, "bin": { "electron-builder": "cli.js", "install-app-deps": "install-app-deps.js" } }, "sha512-poRgAtUHHOnlzZnc9PK4nzG53xh74wj2Jy7jkTrqZ0MWPoHGh1M2+C//hGeYdA+4K8w4yiVCNYoLXF7ySj2Wig=="],
@ -586,8 +599,6 @@
"humanize-ms": ["humanize-ms@1.2.1", "", { "dependencies": { "ms": "^2.0.0" } }, "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ=="], "humanize-ms": ["humanize-ms@1.2.1", "", { "dependencies": { "ms": "^2.0.0" } }, "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ=="],
"iconify-icon": ["iconify-icon@2.3.0", "", { "dependencies": { "@iconify/types": "^2.0.0" } }, "sha512-C0beI9oTDxQz6voI5CKl7MiJf0Lw4UU8K4G4t6pcUDClLmCvuMOpcvd8MAztQ2SfoH0iv7WHdxBFjekKPFKH2Q=="],
"iconv-corefoundation": ["iconv-corefoundation@1.1.7", "", { "dependencies": { "cli-truncate": "^2.1.0", "node-addon-api": "^1.6.3" }, "os": "darwin" }, "sha512-T10qvkw0zz4wnm560lOEg0PovVqUXuOFhhHAkixw8/sycy7TJt7v/RrkEKEQnAw2viPSJu6iAkErxnzR0g8PpQ=="], "iconv-corefoundation": ["iconv-corefoundation@1.1.7", "", { "dependencies": { "cli-truncate": "^2.1.0", "node-addon-api": "^1.6.3" }, "os": "darwin" }, "sha512-T10qvkw0zz4wnm560lOEg0PovVqUXuOFhhHAkixw8/sycy7TJt7v/RrkEKEQnAw2viPSJu6iAkErxnzR0g8PpQ=="],
"iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="], "iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="],
@ -656,27 +667,27 @@
"light-bolt11-decoder": ["light-bolt11-decoder@3.2.0", "", { "dependencies": { "@scure/base": "1.1.1" } }, "sha512-3QEofgiBOP4Ehs9BI+RkZdXZNtSys0nsJ6fyGeSiAGCBsMwHGUDS/JQlY/sTnWs91A2Nh0S9XXfA8Sy9g6QpuQ=="], "light-bolt11-decoder": ["light-bolt11-decoder@3.2.0", "", { "dependencies": { "@scure/base": "1.1.1" } }, "sha512-3QEofgiBOP4Ehs9BI+RkZdXZNtSys0nsJ6fyGeSiAGCBsMwHGUDS/JQlY/sTnWs91A2Nh0S9XXfA8Sy9g6QpuQ=="],
"lightningcss": ["lightningcss@1.29.1", "", { "dependencies": { "detect-libc": "^1.0.3" }, "optionalDependencies": { "lightningcss-darwin-arm64": "1.29.1", "lightningcss-darwin-x64": "1.29.1", "lightningcss-freebsd-x64": "1.29.1", "lightningcss-linux-arm-gnueabihf": "1.29.1", "lightningcss-linux-arm64-gnu": "1.29.1", "lightningcss-linux-arm64-musl": "1.29.1", "lightningcss-linux-x64-gnu": "1.29.1", "lightningcss-linux-x64-musl": "1.29.1", "lightningcss-win32-arm64-msvc": "1.29.1", "lightningcss-win32-x64-msvc": "1.29.1" } }, "sha512-FmGoeD4S05ewj+AkhTY+D+myDvXI6eL27FjHIjoyUkO/uw7WZD1fBVs0QxeYWa7E17CUHJaYX/RUGISCtcrG4Q=="], "lightningcss": ["lightningcss@1.29.2", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-darwin-arm64": "1.29.2", "lightningcss-darwin-x64": "1.29.2", "lightningcss-freebsd-x64": "1.29.2", "lightningcss-linux-arm-gnueabihf": "1.29.2", "lightningcss-linux-arm64-gnu": "1.29.2", "lightningcss-linux-arm64-musl": "1.29.2", "lightningcss-linux-x64-gnu": "1.29.2", "lightningcss-linux-x64-musl": "1.29.2", "lightningcss-win32-arm64-msvc": "1.29.2", "lightningcss-win32-x64-msvc": "1.29.2" } }, "sha512-6b6gd/RUXKaw5keVdSEtqFVdzWnU5jMxTUjA2bVcMNPLwSQ08Sv/UodBVtETLCn7k4S1Ibxwh7k68IwLZPgKaA=="],
"lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.29.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-HtR5XJ5A0lvCqYAoSv2QdZZyoHNttBpa5EP9aNuzBQeKGfbyH5+UipLWvVzpP4Uml5ej4BYs5I9Lco9u1fECqw=="], "lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.29.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-cK/eMabSViKn/PG8U/a7aCorpeKLMlK0bQeNHmdb7qUnBkNPnL+oV5DjJUo0kqWsJUapZsM4jCfYItbqBDvlcA=="],
"lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.29.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-k33G9IzKUpHy/J/3+9MCO4e+PzaFblsgBjSGlpAaFikeBFm8B/CkO3cKU9oI4g+fjS2KlkLM/Bza9K/aw8wsNA=="], "lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.29.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-j5qYxamyQw4kDXX5hnnCKMf3mLlHvG44f24Qyi2965/Ycz829MYqjrVg2H8BidybHBp9kom4D7DR5VqCKDXS0w=="],
"lightningcss-freebsd-x64": ["lightningcss-freebsd-x64@1.29.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-0SUW22fv/8kln2LnIdOCmSuXnxgxVC276W5KLTwoehiO0hxkacBxjHOL5EtHD8BAXg2BvuhsJPmVMasvby3LiQ=="], "lightningcss-freebsd-x64": ["lightningcss-freebsd-x64@1.29.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-wDk7M2tM78Ii8ek9YjnY8MjV5f5JN2qNVO+/0BAGZRvXKtQrBC4/cn4ssQIpKIPP44YXw6gFdpUF+Ps+RGsCwg=="],
"lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.29.1", "", { "os": "linux", "cpu": "arm" }, "sha512-sD32pFvlR0kDlqsOZmYqH/68SqUMPNj+0pucGxToXZi4XZgZmqeX/NkxNKCPsswAXU3UeYgDSpGhu05eAufjDg=="], "lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.29.2", "", { "os": "linux", "cpu": "arm" }, "sha512-IRUrOrAF2Z+KExdExe3Rz7NSTuuJ2HvCGlMKoquK5pjvo2JY4Rybr+NrKnq0U0hZnx5AnGsuFHjGnNT14w26sg=="],
"lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.29.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-0+vClRIZ6mmJl/dxGuRsE197o1HDEeeRk6nzycSy2GofC2JsY4ifCRnvUWf/CUBQmlrvMzt6SMQNMSEu22csWQ=="], "lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.29.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-KKCpOlmhdjvUTX/mBuaKemp0oeDIBBLFiU5Fnqxh1/DZ4JPZi4evEH7TKoSBFOSOV3J7iEmmBaw/8dpiUvRKlQ=="],
"lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.29.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-UKMFrG4rL/uHNgelBsDwJcBqVpzNJbzsKkbI3Ja5fg00sgQnHw/VrzUTEc4jhZ+AN2BvQYz/tkHu4vt1kLuJyw=="], "lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.29.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-Q64eM1bPlOOUgxFmoPUefqzY1yV3ctFPE6d/Vt7WzLW4rKTv7MyYNky+FWxRpLkNASTnKQUaiMJ87zNODIrrKQ=="],
"lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.29.1", "", { "os": "linux", "cpu": "x64" }, "sha512-u1S+xdODy/eEtjADqirA774y3jLcm8RPtYztwReEXoZKdzgsHYPl0s5V52Tst+GKzqjebkULT86XMSxejzfISw=="], "lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.29.2", "", { "os": "linux", "cpu": "x64" }, "sha512-0v6idDCPG6epLXtBH/RPkHvYx74CVziHo6TMYga8O2EiQApnUPZsbR9nFNrg2cgBzk1AYqEd95TlrsL7nYABQg=="],
"lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.29.1", "", { "os": "linux", "cpu": "x64" }, "sha512-L0Tx0DtaNUTzXv0lbGCLB/c/qEADanHbu4QdcNOXLIe1i8i22rZRpbT3gpWYsCh9aSL9zFujY/WmEXIatWvXbw=="], "lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.29.2", "", { "os": "linux", "cpu": "x64" }, "sha512-rMpz2yawkgGT8RULc5S4WiZopVMOFWjiItBT7aSfDX4NQav6M44rhn5hjtkKzB+wMTRlLLqxkeYEtQ3dd9696w=="],
"lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.29.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-QoOVnkIEFfbW4xPi+dpdft/zAKmgLgsRHfJalEPYuJDOWf7cLQzYg0DEh8/sn737FaeMJxHZRc1oBreiwZCjog=="], "lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.29.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-nL7zRW6evGQqYVu/bKGK+zShyz8OVzsCotFgc7judbt6wnB2KbiKKJwBE4SGoDBQ1O94RjW4asrCjQL4i8Fhbw=="],
"lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.29.1", "", { "os": "win32", "cpu": "x64" }, "sha512-NygcbThNBe4JElP+olyTI/doBNGJvLs3bFCRPdvuCcxZCcCZ71B858IHpdm7L1btZex0FvCmM17FK98Y9MRy1Q=="], "lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.29.2", "", { "os": "win32", "cpu": "x64" }, "sha512-EdIUW3B2vLuHmv7urfzMI/h2fmlnOQBk1xlsDxkN1tCWKjNFjfLhGxYk8C8mzpSfr+A6jFFIi8fU6LbQGsRWjA=="],
"linkify-it": ["linkify-it@5.0.0", "", { "dependencies": { "uc.micro": "^2.0.0" } }, "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ=="], "linkify-it": ["linkify-it@5.0.0", "", { "dependencies": { "uc.micro": "^2.0.0" } }, "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ=="],
@ -858,47 +869,47 @@
"sanitize-filename": ["sanitize-filename@1.6.3", "", { "dependencies": { "truncate-utf8-bytes": "^1.0.0" } }, "sha512-y/52Mcy7aw3gRm7IrcGDFx/bCk4AhRh2eI9luHOQM86nZsqwiRkkq2GekHXBBD+SmPidc8i2PqtYZl+pWJ8Oeg=="], "sanitize-filename": ["sanitize-filename@1.6.3", "", { "dependencies": { "truncate-utf8-bytes": "^1.0.0" } }, "sha512-y/52Mcy7aw3gRm7IrcGDFx/bCk4AhRh2eI9luHOQM86nZsqwiRkkq2GekHXBBD+SmPidc8i2PqtYZl+pWJ8Oeg=="],
"sass-embedded": ["sass-embedded@1.85.0", "", { "dependencies": { "@bufbuild/protobuf": "^2.0.0", "buffer-builder": "^0.2.0", "colorjs.io": "^0.5.0", "immutable": "^5.0.2", "rxjs": "^7.4.0", "supports-color": "^8.1.1", "sync-child-process": "^1.0.2", "varint": "^6.0.0" }, "optionalDependencies": { "sass-embedded-android-arm": "1.85.0", "sass-embedded-android-arm64": "1.85.0", "sass-embedded-android-ia32": "1.85.0", "sass-embedded-android-riscv64": "1.85.0", "sass-embedded-android-x64": "1.85.0", "sass-embedded-darwin-arm64": "1.85.0", "sass-embedded-darwin-x64": "1.85.0", "sass-embedded-linux-arm": "1.85.0", "sass-embedded-linux-arm64": "1.85.0", "sass-embedded-linux-ia32": "1.85.0", "sass-embedded-linux-musl-arm": "1.85.0", "sass-embedded-linux-musl-arm64": "1.85.0", "sass-embedded-linux-musl-ia32": "1.85.0", "sass-embedded-linux-musl-riscv64": "1.85.0", "sass-embedded-linux-musl-x64": "1.85.0", "sass-embedded-linux-riscv64": "1.85.0", "sass-embedded-linux-x64": "1.85.0", "sass-embedded-win32-arm64": "1.85.0", "sass-embedded-win32-ia32": "1.85.0", "sass-embedded-win32-x64": "1.85.0" }, "bin": { "sass": "dist/bin/sass.js" } }, "sha512-x3Vv54g0jv1aPSW8OTA/0GzQCs/HMQOjIkLtZJ3Xsn/I4vnyjKbVTQmFTax9bQjldqLEEkdbvy6ES/cOOnYNwA=="], "sass-embedded": ["sass-embedded@1.85.1", "", { "dependencies": { "@bufbuild/protobuf": "^2.0.0", "buffer-builder": "^0.2.0", "colorjs.io": "^0.5.0", "immutable": "^5.0.2", "rxjs": "^7.4.0", "supports-color": "^8.1.1", "sync-child-process": "^1.0.2", "varint": "^6.0.0" }, "optionalDependencies": { "sass-embedded-android-arm": "1.85.1", "sass-embedded-android-arm64": "1.85.1", "sass-embedded-android-ia32": "1.85.1", "sass-embedded-android-riscv64": "1.85.1", "sass-embedded-android-x64": "1.85.1", "sass-embedded-darwin-arm64": "1.85.1", "sass-embedded-darwin-x64": "1.85.1", "sass-embedded-linux-arm": "1.85.1", "sass-embedded-linux-arm64": "1.85.1", "sass-embedded-linux-ia32": "1.85.1", "sass-embedded-linux-musl-arm": "1.85.1", "sass-embedded-linux-musl-arm64": "1.85.1", "sass-embedded-linux-musl-ia32": "1.85.1", "sass-embedded-linux-musl-riscv64": "1.85.1", "sass-embedded-linux-musl-x64": "1.85.1", "sass-embedded-linux-riscv64": "1.85.1", "sass-embedded-linux-x64": "1.85.1", "sass-embedded-win32-arm64": "1.85.1", "sass-embedded-win32-ia32": "1.85.1", "sass-embedded-win32-x64": "1.85.1" }, "bin": { "sass": "dist/bin/sass.js" } }, "sha512-0i+3h2Df/c71afluxC1SXqyyMmJlnKWfu9ZGdzwuKRM1OftEa2XM2myt5tR36CF3PanYrMjFKtRIj8PfSf838w=="],
"sass-embedded-android-arm": ["sass-embedded-android-arm@1.85.0", "", { "os": "android", "cpu": "arm" }, "sha512-pPBT7Ad6G8Mlao8ypVNXW2ya7I/Bhcny+RYZ/EmrunEXfhzCNp4PWV2VAweitPO9RnPIJwvUTkLc8Fu6K3nVmw=="], "sass-embedded-android-arm": ["sass-embedded-android-arm@1.85.1", "", { "os": "android", "cpu": "arm" }, "sha512-GkcgUGMZtEF9gheuE1dxCU0ZSAifuaFXi/aX7ZXvjtdwmTl9Zc/OHR9oiUJkc8IW9UI7H8TuwlTAA8+SwgwIeQ=="],
"sass-embedded-android-arm64": ["sass-embedded-android-arm64@1.85.0", "", { "os": "android", "cpu": "arm64" }, "sha512-4itDzRwezwrW8+YzMLIwHtMeH+qrBNdBsRn9lTVI15K+cNLC8z5JWJi6UCZ8TNNZr9LDBfsh5jUdjSub0yF7jg=="], "sass-embedded-android-arm64": ["sass-embedded-android-arm64@1.85.1", "", { "os": "android", "cpu": "arm64" }, "sha512-27oRheqNA3SJM2hAxpVbs7mCKUwKPWmEEhyiNFpBINb5ELVLg+Ck5RsGg+SJmo130ul5YX0vinmVB5uPWc8X5w=="],
"sass-embedded-android-ia32": ["sass-embedded-android-ia32@1.85.0", "", { "os": "android", "cpu": "ia32" }, "sha512-bwqKq95hzbGbMTeXCMQhH7yEdc2xJVwIXj7rGdD3McvyFWbED6362XRFFPI5YyjfD2wRJd9yWLh/hn+6VyjcYA=="], "sass-embedded-android-ia32": ["sass-embedded-android-ia32@1.85.1", "", { "os": "android", "cpu": "ia32" }, "sha512-f3x16NyRgtXFksIaO/xXKrUhttUBv8V0XsAR2Dhdb/yz4yrDrhzw9Wh8fmw7PlQqECcQvFaoDr3XIIM6lKzasw=="],
"sass-embedded-android-riscv64": ["sass-embedded-android-riscv64@1.85.0", "", { "os": "android", "cpu": "none" }, "sha512-Fgkgay+5EePJXZFHR5Vlkutnsmox2V6nX4U3mfGbSN1xjLRm8F5ST72V2s5Z0mnIFpGvEu/v7hfptgViqMvaxg=="], "sass-embedded-android-riscv64": ["sass-embedded-android-riscv64@1.85.1", "", { "os": "android", "cpu": "none" }, "sha512-IP6OijpJ8Mqo7XqCe0LsuZVbAxEFVboa0kXqqR5K55LebEplsTIA2GnmRyMay3Yr/2FVGsZbCb6Wlgkw23eCiA=="],
"sass-embedded-android-x64": ["sass-embedded-android-x64@1.85.0", "", { "os": "android", "cpu": "x64" }, "sha512-/bG3JgTn3eoIDHCiJNVkLeJgUesat4ghxqYmKMZUJx++4e6iKCDj8XwQTJAgm+QDrsPKXHBacHEANJ9LEAuTqg=="], "sass-embedded-android-x64": ["sass-embedded-android-x64@1.85.1", "", { "os": "android", "cpu": "x64" }, "sha512-Mh7CA53wR3ADvXAYipFc/R3vV4PVOzoKwWzPxmq+7i8UZrtsVjKONxGtqWe9JG1mna0C9CRZAx0sv/BzbOJxWg=="],
"sass-embedded-darwin-arm64": ["sass-embedded-darwin-arm64@1.85.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-plp8TyMz97YFBCB3ndftEvoW29vyfsSBJILM5U84cGzr06SvLh/Npjj8psfUeRw+upEk1zkFtw5u61sRCdgwIw=="], "sass-embedded-darwin-arm64": ["sass-embedded-darwin-arm64@1.85.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-msWxzhvcP9hqGVegxVePVEfv9mVNTlUgGr6k7O7Ihji702mbtrH/lKwF4aRkkt4g1j7tv10+JtQXmTNi/pi9kA=="],
"sass-embedded-darwin-x64": ["sass-embedded-darwin-x64@1.85.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-LP8Zv8DG57Gn6PmSwWzC0gEZUsGdg36Ps3m0i1fVTOelql7N3HZIrlPYRjJvidL8ZlB3ISxNANebTREUHn/wkQ=="], "sass-embedded-darwin-x64": ["sass-embedded-darwin-x64@1.85.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-J4UFHUiyI9Z+mwYMwz11Ky9TYr3hY1fCxeQddjNGL/+ovldtb0yAIHvoVM0BGprQDm5JqhtUk8KyJ3RMJqpaAA=="],
"sass-embedded-linux-arm": ["sass-embedded-linux-arm@1.85.0", "", { "os": "linux", "cpu": "arm" }, "sha512-18xOAEfazJt1MMVS2TRHV94n81VyMnywOoJ7/S7I79qno/zx26OoqqP4XvH107xu8+mZ9Gg54LrUH6ZcgHk08g=="], "sass-embedded-linux-arm": ["sass-embedded-linux-arm@1.85.1", "", { "os": "linux", "cpu": "arm" }, "sha512-X0fDh95nNSw1wfRlnkE4oscoEA5Au4nnk785s9jghPFkTBg+A+5uB6trCjf0fM22+Iw6kiP4YYmDdw3BqxAKLQ=="],
"sass-embedded-linux-arm64": ["sass-embedded-linux-arm64@1.85.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-JRIRKVOY5Y8M1zlUOv9AQGju4P6lj8i5vLJZsVYVN/uY8Cd2dDJZPC8EOhjntp+IpF8AOGIHqCeCkHBceIyIjA=="], "sass-embedded-linux-arm64": ["sass-embedded-linux-arm64@1.85.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-jGadetB03BMFG2rq3OXub/uvC/lGpbQOiLGEz3NLb2nRZWyauRhzDtvZqkr6BEhxgIWtMtz2020yD8ZJSw/r2w=="],
"sass-embedded-linux-ia32": ["sass-embedded-linux-ia32@1.85.0", "", { "os": "linux", "cpu": "ia32" }, "sha512-4JH+h+gLt9So22nNPQtsKojEsLzjld9ol3zWcOtMGclv+HojZGbCuhJUrLUcK72F8adXYsULmWhJPKROLIwYMA=="], "sass-embedded-linux-ia32": ["sass-embedded-linux-ia32@1.85.1", "", { "os": "linux", "cpu": "ia32" }, "sha512-7HlYY90d9mitDtNi5s+S+5wYZrTVbkBH2/kf7ixrzh2BFfT0YM81UHLJRnGX93y9aOMBL6DSZAIfkt1RsV9bkQ=="],
"sass-embedded-linux-musl-arm": ["sass-embedded-linux-musl-arm@1.85.0", "", { "os": "linux", "cpu": "arm" }, "sha512-Z1j4ageDVFihqNUBnm89fxY46pY0zD/Clp1D3ZdI7S+D280+AEpbm5vMoH8LLhBQfQLf2w7H++SZGpQwrisudQ=="], "sass-embedded-linux-musl-arm": ["sass-embedded-linux-musl-arm@1.85.1", "", { "os": "linux", "cpu": "arm" }, "sha512-5vcdEqE8QZnu6i6shZo7x2N36V7YUoFotWj2rGekII5ty7Nkaj+VtZhUEOp9tAzEOlaFuDp5CyO1kUCvweT64A=="],
"sass-embedded-linux-musl-arm64": ["sass-embedded-linux-musl-arm64@1.85.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-aoQjUjK28bvdw9XKTjQeayn8oWQ2QqvoTD11myklGd3IHH7Jj0nwXUstI4NxDueCKt3wghuZoIQkjOheReQxlg=="], "sass-embedded-linux-musl-arm64": ["sass-embedded-linux-musl-arm64@1.85.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-FLkIT0p18XOkR6wryJ13LqGBDsrYev2dRk9dtiU18NCpNXruKsdBQ1ZnWHVKB3h1dA9lFyEEisC0sooKdNfeOQ=="],
"sass-embedded-linux-musl-ia32": ["sass-embedded-linux-musl-ia32@1.85.0", "", { "os": "linux", "cpu": "ia32" }, "sha512-/cJCSXOfXmQFH8deE+3U9x+BSz8i0d1Tt9gKV/Gat1Xm43Oumw8pmZgno+cDuGjYQInr9ryW5121pTMlj/PBXQ=="], "sass-embedded-linux-musl-ia32": ["sass-embedded-linux-musl-ia32@1.85.1", "", { "os": "linux", "cpu": "ia32" }, "sha512-N1093T84zQJor1yyIAdYScB5eAuQarGK1tKgZ4uTnxVlgA7Xi1lXV8Eh7ox9sDqKCaWkVQ3MjqU26vYRBeRWyw=="],
"sass-embedded-linux-musl-riscv64": ["sass-embedded-linux-musl-riscv64@1.85.0", "", { "os": "linux", "cpu": "none" }, "sha512-l+FJxMXkmg42RZq5RFKXg4InX0IA7yEiPHe4kVSdrczP7z3NLxk+W9wVkPnoRKYIMe1qZPPQ25y0TgI4HNWouA=="], "sass-embedded-linux-musl-riscv64": ["sass-embedded-linux-musl-riscv64@1.85.1", "", { "os": "linux", "cpu": "none" }, "sha512-WRsZS/7qlfYXsa93FBpSruieuURIu7ySfFhzYfF1IbKrNAGwmbduutkHZh2ddm5/vQMvQ0Rdosgv+CslaQHMcw=="],
"sass-embedded-linux-musl-x64": ["sass-embedded-linux-musl-x64@1.85.0", "", { "os": "linux", "cpu": "x64" }, "sha512-M9ffjcYfFcRvkFA6V3DpOS955AyvmpvPAhL/xNK45d/ma1n1ehTWpd24tVeKiNK5CZkNjjMEfyw2fHa6MpqmEA=="], "sass-embedded-linux-musl-x64": ["sass-embedded-linux-musl-x64@1.85.1", "", { "os": "linux", "cpu": "x64" }, "sha512-+OlLIilA5TnP0YEqTQ8yZtkW+bJIQYvzoGoNLUEskeyeGuOiIyn2CwL6G4JQB4xZQFaxPHb7JD3EueFkQbH0Pw=="],
"sass-embedded-linux-riscv64": ["sass-embedded-linux-riscv64@1.85.0", "", { "os": "linux", "cpu": "none" }, "sha512-yqPXQWfM+qiIPkfn++48GOlbmSvUZIyL9nwFstBk0k4x40UhbhilfknqeTUpxoHfQzylTGVhrm5JE7MjM+LNZA=="], "sass-embedded-linux-riscv64": ["sass-embedded-linux-riscv64@1.85.1", "", { "os": "linux", "cpu": "none" }, "sha512-mKKlOwMGLN7yP1p0gB5yG/HX4fYLnpWaqstNuOOXH+fOzTaNg0+1hALg0H0CDIqypPO74M5MS9T6FAJZGdT6dQ=="],
"sass-embedded-linux-x64": ["sass-embedded-linux-x64@1.85.0", "", { "os": "linux", "cpu": "x64" }, "sha512-NTDeQFZcuVR7COoaRy8pZD6/+QznwBR8kVFsj7NpmvX9aJ7TX/q+OQZHX7Bfb3tsfKXhf1YZozegPuYxRnMKAQ=="], "sass-embedded-linux-x64": ["sass-embedded-linux-x64@1.85.1", "", { "os": "linux", "cpu": "x64" }, "sha512-uKRTv0z8NgtHV7xSren78+yoWB79sNi7TMqI7Bxd8fcRNIgHQSA8QBdF8led2ETC004hr8h71BrY60RPO+SSvA=="],
"sass-embedded-win32-arm64": ["sass-embedded-win32-arm64@1.85.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-gO0VAuxC4AdV+uZYJESRWVVHQWCGzNs0C3OKCAdH4r1vGRugooMi7J/5wbwUdXDA1MV9ICfhlKsph2n3GiPdqA=="], "sass-embedded-win32-arm64": ["sass-embedded-win32-arm64@1.85.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-/GMiZXBOc6AEMBC3g25Rp+x8fq9Z6Ql7037l5rajBPhZ+DdFwtdHY0Ou3oIU6XuWUwD06U3ii4XufXVFhsP6PA=="],
"sass-embedded-win32-ia32": ["sass-embedded-win32-ia32@1.85.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-PCyn6xeFIBUgBceNypuf73/5DWF2VWPlPqPuBprPsTvpZOMUJeBtP+Lf4mnu3dNy1z76mYVnpaCnQmzZ0zHZaA=="], "sass-embedded-win32-ia32": ["sass-embedded-win32-ia32@1.85.1", "", { "os": "win32", "cpu": "ia32" }, "sha512-L+4BWkKKBGFOKVQ2PQ5HwFfkM5FvTf1Xx2VSRvEWt9HxPXp6SPDho6zC8fqNQ3hSjoaoASEIJcSvgfdQYO0gdg=="],
"sass-embedded-win32-x64": ["sass-embedded-win32-x64@1.85.0", "", { "os": "win32", "cpu": "x64" }, "sha512-AknE2jLp6OBwrR5hQ8pDsG94KhJCeSheFJ2xgbnk8RUjZX909JiNbgh2sNt9LG+RXf4xZa55dDL537gZoCx/iw=="], "sass-embedded-win32-x64": ["sass-embedded-win32-x64@1.85.1", "", { "os": "win32", "cpu": "x64" }, "sha512-/FO0AGKWxVfCk4GKsC0yXWBpUZdySe3YAAbQQL0lL6xUd1OiUY8Kow6g4Kc1TB/+z0iuQKKTqI/acJMEYl4iTQ=="],
"sax": ["sax@1.4.1", "", {}, "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg=="], "sax": ["sax@1.4.1", "", {}, "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg=="],
@ -1010,7 +1021,7 @@
"verror": ["verror@1.10.1", "", { "dependencies": { "assert-plus": "^1.0.0", "core-util-is": "1.0.2", "extsprintf": "^1.2.0" } }, "sha512-veufcmxri4e3XSrT0xwfUR7kguIkaxBeosDg00yDWhk49wdwkSUrvvsm7nc75e1PUyvIeZj6nS8VQRYz2/S4Xg=="], "verror": ["verror@1.10.1", "", { "dependencies": { "assert-plus": "^1.0.0", "core-util-is": "1.0.2", "extsprintf": "^1.2.0" } }, "sha512-veufcmxri4e3XSrT0xwfUR7kguIkaxBeosDg00yDWhk49wdwkSUrvvsm7nc75e1PUyvIeZj6nS8VQRYz2/S4Xg=="],
"vite": ["vite@6.1.1", "", { "dependencies": { "esbuild": "^0.24.2", "postcss": "^8.5.2", "rollup": "^4.30.1" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-4GgM54XrwRfrOp297aIYspIti66k56v16ZnqHvrIM7mG+HjDlAwS7p+Srr7J6fGvEdOJ5JcQ/D9T7HhtdXDTzA=="], "vite": ["vite@6.2.1", "", { "dependencies": { "esbuild": "^0.25.0", "postcss": "^8.5.3", "rollup": "^4.30.1" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-n2GnqDb6XPhlt9B8olZPrgMD/es/Nd1RdChF6CBD/fHW6pUyUTt2sQW2fPRX5GiD9XEa6+8A6A4f2vT6pSsE7Q=="],
"wcwidth": ["wcwidth@1.0.1", "", { "dependencies": { "defaults": "^1.0.3" } }, "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg=="], "wcwidth": ["wcwidth@1.0.1", "", { "dependencies": { "defaults": "^1.0.3" } }, "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg=="],
@ -1058,8 +1069,6 @@
"@electron/osx-sign/isbinaryfile": ["isbinaryfile@4.0.10", "", {}, "sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw=="], "@electron/osx-sign/isbinaryfile": ["isbinaryfile@4.0.10", "", {}, "sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw=="],
"@electron/rebuild/detect-libc": ["detect-libc@2.0.3", "", {}, "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw=="],
"@electron/rebuild/semver": ["semver@7.7.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA=="], "@electron/rebuild/semver": ["semver@7.7.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA=="],
"@electron/universal/fs-extra": ["fs-extra@11.3.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew=="], "@electron/universal/fs-extra": ["fs-extra@11.3.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew=="],
@ -1094,6 +1103,18 @@
"@scure/bip39/@scure/base": ["@scure/base@1.1.1", "", {}, "sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA=="], "@scure/bip39/@scure/base": ["@scure/base@1.1.1", "", {}, "sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA=="],
"@types/cacheable-request/@types/node": ["@types/node@22.13.5", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-+lTU0PxZXn0Dr1NBtC7Y8cR21AJr87dLLU953CWA6pMxxv/UDc7jYAY90upcrie1nRcD6XNG5HOYEDtgW5TxAg=="],
"@types/fs-extra/@types/node": ["@types/node@22.13.5", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-+lTU0PxZXn0Dr1NBtC7Y8cR21AJr87dLLU953CWA6pMxxv/UDc7jYAY90upcrie1nRcD6XNG5HOYEDtgW5TxAg=="],
"@types/keyv/@types/node": ["@types/node@22.13.5", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-+lTU0PxZXn0Dr1NBtC7Y8cR21AJr87dLLU953CWA6pMxxv/UDc7jYAY90upcrie1nRcD6XNG5HOYEDtgW5TxAg=="],
"@types/plist/@types/node": ["@types/node@22.13.5", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-+lTU0PxZXn0Dr1NBtC7Y8cR21AJr87dLLU953CWA6pMxxv/UDc7jYAY90upcrie1nRcD6XNG5HOYEDtgW5TxAg=="],
"@types/responselike/@types/node": ["@types/node@22.13.5", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-+lTU0PxZXn0Dr1NBtC7Y8cR21AJr87dLLU953CWA6pMxxv/UDc7jYAY90upcrie1nRcD6XNG5HOYEDtgW5TxAg=="],
"@types/yauzl/@types/node": ["@types/node@22.13.5", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-+lTU0PxZXn0Dr1NBtC7Y8cR21AJr87dLLU953CWA6pMxxv/UDc7jYAY90upcrie1nRcD6XNG5HOYEDtgW5TxAg=="],
"app-builder-lib/semver": ["semver@7.7.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA=="], "app-builder-lib/semver": ["semver@7.7.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA=="],
"archiver-utils/glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="], "archiver-utils/glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="],
@ -1186,6 +1207,8 @@
"string_decoder/safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="], "string_decoder/safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="],
"vite/esbuild": ["esbuild@0.25.1", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.1", "@esbuild/android-arm": "0.25.1", "@esbuild/android-arm64": "0.25.1", "@esbuild/android-x64": "0.25.1", "@esbuild/darwin-arm64": "0.25.1", "@esbuild/darwin-x64": "0.25.1", "@esbuild/freebsd-arm64": "0.25.1", "@esbuild/freebsd-x64": "0.25.1", "@esbuild/linux-arm": "0.25.1", "@esbuild/linux-arm64": "0.25.1", "@esbuild/linux-ia32": "0.25.1", "@esbuild/linux-loong64": "0.25.1", "@esbuild/linux-mips64el": "0.25.1", "@esbuild/linux-ppc64": "0.25.1", "@esbuild/linux-riscv64": "0.25.1", "@esbuild/linux-s390x": "0.25.1", "@esbuild/linux-x64": "0.25.1", "@esbuild/netbsd-arm64": "0.25.1", "@esbuild/netbsd-x64": "0.25.1", "@esbuild/openbsd-arm64": "0.25.1", "@esbuild/openbsd-x64": "0.25.1", "@esbuild/sunos-x64": "0.25.1", "@esbuild/win32-arm64": "0.25.1", "@esbuild/win32-ia32": "0.25.1", "@esbuild/win32-x64": "0.25.1" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-BGO5LtrGC7vxnqucAe/rmvKdJllfGaYWdyABvyMoXQlfYMb2bbRuReWR5tEGE//4LcNJj9XrkovTqNYRFZHAMQ=="],
"websocket/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], "websocket/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="],
"zip-stream/archiver-utils": ["archiver-utils@3.0.4", "", { "dependencies": { "glob": "^7.2.3", "graceful-fs": "^4.2.0", "lazystream": "^1.0.0", "lodash.defaults": "^4.2.0", "lodash.difference": "^4.5.0", "lodash.flatten": "^4.4.0", "lodash.isplainobject": "^4.0.6", "lodash.union": "^4.6.0", "normalize-path": "^3.0.0", "readable-stream": "^3.6.0" } }, "sha512-KVgf4XQVrTjhyWmx6cte4RxonPLR9onExufI1jhvw/MQ4BB6IsZD5gT8Lq+u/+pRkWna/6JoHpiQioaqFP5Rzw=="], "zip-stream/archiver-utils": ["archiver-utils@3.0.4", "", { "dependencies": { "glob": "^7.2.3", "graceful-fs": "^4.2.0", "lazystream": "^1.0.0", "lodash.defaults": "^4.2.0", "lodash.difference": "^4.5.0", "lodash.flatten": "^4.4.0", "lodash.isplainobject": "^4.0.6", "lodash.union": "^4.6.0", "normalize-path": "^3.0.0", "readable-stream": "^3.6.0" } }, "sha512-KVgf4XQVrTjhyWmx6cte4RxonPLR9onExufI1jhvw/MQ4BB6IsZD5gT8Lq+u/+pRkWna/6JoHpiQioaqFP5Rzw=="],
@ -1232,6 +1255,56 @@
"rimraf/glob/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="], "rimraf/glob/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="],
"vite/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.1", "", { "os": "aix", "cpu": "ppc64" }, "sha512-kfYGy8IdzTGy+z0vFGvExZtxkFlA4zAxgKEahG9KE1ScBjpQnFsNOX8KTU5ojNru5ed5CVoJYXFtoxaq5nFbjQ=="],
"vite/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.25.1", "", { "os": "android", "cpu": "arm" }, "sha512-dp+MshLYux6j/JjdqVLnMglQlFu+MuVeNrmT5nk6q07wNhCdSnB7QZj+7G8VMUGh1q+vj2Bq8kRsuyA00I/k+Q=="],
"vite/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.1", "", { "os": "android", "cpu": "arm64" }, "sha512-50tM0zCJW5kGqgG7fQ7IHvQOcAn9TKiVRuQ/lN0xR+T2lzEFvAi1ZcS8DiksFcEpf1t/GYOeOfCAgDHFpkiSmA=="],
"vite/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.25.1", "", { "os": "android", "cpu": "x64" }, "sha512-GCj6WfUtNldqUzYkN/ITtlhwQqGWu9S45vUXs7EIYf+7rCiiqH9bCloatO9VhxsL0Pji+PF4Lz2XXCES+Q8hDw=="],
"vite/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-5hEZKPf+nQjYoSr/elb62U19/l1mZDdqidGfmFutVUjjUZrOazAtwK+Kr+3y0C/oeJfLlxo9fXb1w7L+P7E4FQ=="],
"vite/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-hxVnwL2Dqs3fM1IWq8Iezh0cX7ZGdVhbTfnOy5uURtao5OIVCEyj9xIzemDi7sRvKsuSdtCAhMKarxqtlyVyfA=="],
"vite/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.1", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-1MrCZs0fZa2g8E+FUo2ipw6jw5qqQiH+tERoS5fAfKnRx6NXH31tXBKI3VpmLijLH6yriMZsxJtaXUyFt/8Y4A=="],
"vite/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-0IZWLiTyz7nm0xuIs0q1Y3QWJC52R8aSXxe40VUxm6BB1RNmkODtW6LHvWRrGiICulcX7ZvyH6h5fqdLu4gkww=="],
"vite/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.1", "", { "os": "linux", "cpu": "arm" }, "sha512-NdKOhS4u7JhDKw9G3cY6sWqFcnLITn6SqivVArbzIaf3cemShqfLGHYMx8Xlm/lBit3/5d7kXvriTUGa5YViuQ=="],
"vite/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-jaN3dHi0/DDPelk0nLcXRm1q7DNJpjXy7yWaWvbfkPvI+7XNSc/lDOnCLN7gzsyzgu6qSAmgSvP9oXAhP973uQ=="],
"vite/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.1", "", { "os": "linux", "cpu": "ia32" }, "sha512-OJykPaF4v8JidKNGz8c/q1lBO44sQNUQtq1KktJXdBLn1hPod5rE/Hko5ugKKZd+D2+o1a9MFGUEIUwO2YfgkQ=="],
"vite/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.1", "", { "os": "linux", "cpu": "none" }, "sha512-nGfornQj4dzcq5Vp835oM/o21UMlXzn79KobKlcs3Wz9smwiifknLy4xDCLUU0BWp7b/houtdrgUz7nOGnfIYg=="],
"vite/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.1", "", { "os": "linux", "cpu": "none" }, "sha512-1osBbPEFYwIE5IVB/0g2X6i1qInZa1aIoj1TdL4AaAb55xIIgbg8Doq6a5BzYWgr+tEcDzYH67XVnTmUzL+nXg=="],
"vite/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-/6VBJOwUf3TdTvJZ82qF3tbLuWsscd7/1w+D9LH0W/SqUgM5/JJD0lrJ1fVIfZsqB6RFmLCe0Xz3fmZc3WtyVg=="],
"vite/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.1", "", { "os": "linux", "cpu": "none" }, "sha512-nSut/Mx5gnilhcq2yIMLMe3Wl4FK5wx/o0QuuCLMtmJn+WeWYoEGDN1ipcN72g1WHsnIbxGXd4i/MF0gTcuAjQ=="],
"vite/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.1", "", { "os": "linux", "cpu": "s390x" }, "sha512-cEECeLlJNfT8kZHqLarDBQso9a27o2Zd2AQ8USAEoGtejOrCYHNtKP8XQhMDJMtthdF4GBmjR2au3x1udADQQQ=="],
"vite/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.1", "", { "os": "linux", "cpu": "x64" }, "sha512-xbfUhu/gnvSEg+EGovRc+kjBAkrvtk38RlerAzQxvMzlB4fXpCFCeUAYzJvrnhFtdeyVCDANSjJvOvGYoeKzFA=="],
"vite/esbuild/@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.1", "", { "os": "none", "cpu": "arm64" }, "sha512-O96poM2XGhLtpTh+s4+nP7YCCAfb4tJNRVZHfIE7dgmax+yMP2WgMd2OecBuaATHKTHsLWHQeuaxMRnCsH8+5g=="],
"vite/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.1", "", { "os": "none", "cpu": "x64" }, "sha512-X53z6uXip6KFXBQ+Krbx25XHV/NCbzryM6ehOAeAil7X7oa4XIq+394PWGnwaSQ2WRA0KI6PUO6hTO5zeF5ijA=="],
"vite/esbuild/@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.1", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-Na9T3szbXezdzM/Kfs3GcRQNjHzM6GzFBeU1/6IV/npKP5ORtp9zbQjvkDJ47s6BCgaAZnnnu/cY1x342+MvZg=="],
"vite/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.1", "", { "os": "openbsd", "cpu": "x64" }, "sha512-T3H78X2h1tszfRSf+txbt5aOp/e7TAz3ptVKu9Oyir3IAOFPGV6O9c2naym5TOriy1l0nNf6a4X5UXRZSGX/dw=="],
"vite/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.1", "", { "os": "sunos", "cpu": "x64" }, "sha512-2H3RUvcmULO7dIE5EWJH8eubZAI4xw54H1ilJnRNZdeo8dTADEZ21w6J22XBkXqGJbe0+wnNJtw3UXRoLJnFEg=="],
"vite/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-GE7XvrdOzrb+yVKB9KsRMq+7a2U/K5Cf/8grVFRAGJmfADr/e/ODQ134RK2/eeHqYV5eQRFxb1hY7Nr15fv1NQ=="],
"vite/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.1", "", { "os": "win32", "cpu": "ia32" }, "sha512-uOxSJCIcavSiT6UnBhBzE8wy3n0hOkJsBOzy7HDAuTDE++1DJMRRVCPGisULScHL+a/ZwdXPpXD3IyFKjA7K8A=="],
"vite/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.1", "", { "os": "win32", "cpu": "x64" }, "sha512-Y1EQdcfwMSeQN/ujR5VayLOJ1BHaK+ssyk0AEzPjC+t1lITgsnccPqFjb6V+LsTp/9Iov4ysfjxLaGJ9RPtkVg=="],
"websocket/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], "websocket/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="],
"zip-stream/archiver-utils/glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="], "zip-stream/archiver-utils/glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="],

View file

@ -19,30 +19,33 @@
"build:linux": "bun run build && electron-builder --linux", "build:linux": "bun run build && electron-builder --linux",
"start": "electron-vite preview", "start": "electron-vite preview",
"dev": "electron-vite dev", "dev": "electron-vite dev",
"prebuild": "electron-vite build" "prebuild": "electron-vite build",
"lint": "biome check",
"lint:fix": "biome check --write --unsafe",
"postinstall": "bun setup-hooks.js"
}, },
"devDependencies": { "devDependencies": {
"@biomejs/biome": "^1.9.4",
"@electron-toolkit/preload": "^3.0.1", "@electron-toolkit/preload": "^3.0.1",
"@electron-toolkit/utils": "^4.0.0", "@electron-toolkit/utils": "^4.0.0",
"electron-builder": "^25.1.8",
"electron-vite": "^3.0.0",
"electron": "^34.2.0",
"@tsconfig/node22": "^22.0.0", "@tsconfig/node22": "^22.0.0",
"@types/markdown-it": "^14.1.2", "@types/markdown-it": "^14.1.2",
"@types/node": "^22.10.2", "@types/node": "^22.13.10",
"lightningcss": "^1.28.2", "electron": "^34.3.2",
"sass-embedded": "^1.83.0", "electron-builder": "^25.1.8",
"electron-vite": "^3.0.0",
"lightningcss": "^1.29.2",
"sass-embedded": "^1.85.1",
"typescript": "~5.6.3", "typescript": "~5.6.3",
"vite": "^6.0.5" "vite": "^6.2.1"
}, },
"dependencies": { "dependencies": {
"@lit-labs/motion": "^1.0.8", "@lit-labs/motion": "^1.0.8",
"@noble/ciphers": "^1.2.1", "@noble/ciphers": "^1.2.1",
"@nostr-dev-kit/ndk": "^2.10.7", "@nostr-dev-kit/ndk": "^2.12.2",
"@nostr/tools": "npm:@jsr/nostr__tools", "@nostr/tools": "npm:@jsr/nostr__tools",
"@open-wc/lit-helpers": "^0.7.0", "@open-wc/lit-helpers": "^0.7.0",
"@std/encoding": "npm:@jsr/std__encoding", "@std/encoding": "npm:@jsr/std__encoding",
"iconify-icon": "^2.2.0",
"lit": "^3.2.1", "lit": "^3.2.1",
"markdown-it": "^14.1.0" "markdown-it": "^14.1.0"
} }

18
setup-hooks.ts Executable file
View file

@ -0,0 +1,18 @@
#!/usr/bin/env bun
import { spawnSync } from "child_process";
import { resolve } from "path";
const hooksPath = resolve(".hooks");
console.log(`Setting git hooks path to ${hooksPath}...`);
const result = spawnSync("git", ["config", "core.hooksPath", hooksPath], {
stdio: "inherit",
});
if (result.status === 0) {
console.log("Git hooks successfully configured!");
} else {
console.error("Failed to configure git hooks.");
process.exit(1);
}

View file

@ -1,9 +1,9 @@
import { css, html, LitElement } from "lit"; import { LitElement, css, html } from 'lit';
import { customElement, property } from "lit/decorators.js"; import { customElement, property } from 'lit/decorators.js';
import "@components/AppIcon"; import '@components/AppIcon';
@customElement("arx-app-grid") @customElement('arx-app-grid')
export class AppGrid extends LitElement { export class AppGrid extends LitElement {
@property() @property()
apps: { apps: {
@ -59,7 +59,7 @@ export class AppGrid extends LitElement {
.href=${app.href} .href=${app.href}
.name=${app.name} .name=${app.name}
></arx-app-icon> ></arx-app-icon>
` `,
)} )}
</div> </div>
`; `;

View file

@ -1,21 +1,21 @@
import { css, html, LitElement } from "lit"; import { LitElement, css, html } from 'lit';
import { customElement, property } from "lit/decorators.js"; import { customElement, property } from 'lit/decorators.js';
import "@components/EveLink"; import '@components/EveLink';
@customElement("arx-app-icon") @customElement('arx-app-icon')
export class AppIcon extends LitElement { export class AppIcon extends LitElement {
@property() @property()
icon: string | undefined; icon: string | undefined;
@property() @property()
color = "#ff9900"; color = '#ff9900';
@property() @property()
href = "#"; href = '#';
@property() @property()
name = "App"; name = 'App';
static override styles = [ static override styles = [
css` css`
@ -83,15 +83,17 @@ export class AppIcon extends LitElement {
return html` return html`
<arx-eve-link href="${this.href}" class="app-icon"> <arx-eve-link href="${this.href}" class="app-icon">
<div class="icon" style="background-color: ${this.color}"> <div class="icon" style="background-color: ${this.color}">
${this.icon ${
? html`<iconify-icon this.icon
? html`<iconify-icon
icon="${this.icon}" icon="${this.icon}"
class="app-icon" class="app-icon"
width="48" width="48"
height="48" height="48"
color="white" color="white"
></iconify-icon>` ></iconify-icon>`
: ""} : ''
}
</div> </div>
<span class="app-name">${this.name}</span> <span class="app-name">${this.name}</span>
</arx-eve-link> </arx-eve-link>

View file

@ -1,5 +1,5 @@
import { html, css, LitElement } from 'lit'; import { LitElement, css, html } from 'lit';
import { property, customElement } from 'lit/decorators.js'; import { customElement, property } from 'lit/decorators.js';
import './BreadcrumbsItem'; import './BreadcrumbsItem';
@customElement('arx-breadcrumbs') @customElement('arx-breadcrumbs')

View file

@ -1,11 +1,11 @@
import { html, css, LitElement } from "lit"; import { LitElement, css, html } from 'lit';
import { property, customElement } from "lit/decorators.js"; import { customElement, property } from 'lit/decorators.js';
import "@components/EveLink"; import '@components/EveLink';
@customElement("arx-breadcrumbs-item") @customElement('arx-breadcrumbs-item')
export class BreadcrumbsItem extends LitElement { export class BreadcrumbsItem extends LitElement {
@property() text = ""; @property() text = '';
@property() href?: string; @property() href?: string;
@property() index = 0; @property() index = 0;
@ -37,14 +37,14 @@ export class BreadcrumbsItem extends LitElement {
override render() { override render() {
return html` return html`
<li> <li>
${this.index > 0 ${this.index > 0 ? html`<span class="separator" aria-hidden="true">/</span>` : ''}
? html`<span class="separator" aria-hidden="true">/</span>` ${
: ""} this.href
${this.href ? html`<arx-eve-link class="link" href=${this.href}
? html`<arx-eve-link class="link" href=${this.href}
>${this.text}</arx-eve-link >${this.text}</arx-eve-link
>` >`
: html`<span class="secondary">${this.text}</span>`} : html`<span class="secondary">${this.text}</span>`
}
</li> </li>
`; `;
} }

View file

@ -1,4 +1,4 @@
import { html, LitElement, css } from 'lit'; import { LitElement, css, html } from 'lit';
import { customElement, property } from 'lit/decorators.js'; import { customElement, property } from 'lit/decorators.js';
@customElement('arx-error-view') @customElement('arx-error-view')

View file

@ -1,18 +1,18 @@
import { css, html, LitElement } from "lit"; import { LitElement, css, html } from 'lit';
import { customElement, property } from "lit/decorators.js"; import { customElement, property } from 'lit/decorators.js';
@customElement("arx-eve-link") @customElement('arx-eve-link')
export class EveLink extends LitElement { export class EveLink extends LitElement {
@property({ type: String }) href = "#"; @property({ type: String }) href = '#';
@property({ type: String }) target = ""; @property({ type: String }) target = '';
@property({ type: String }) rel = ""; @property({ type: String }) rel = '';
get hrefValue() { get hrefValue() {
let href = this.href; let href = this.href;
if (href.startsWith("javascript:")) return href; if (href.startsWith('javascript:')) return href;
if (href.startsWith("eve://")) href = href.replace("eve://", "#"); if (href.startsWith('eve://')) href = href.replace('eve://', '#');
if (href.startsWith("/")) href = href.replace("/", "#"); if (href.startsWith('/')) href = href.replace('/', '#');
if (!href.startsWith("#")) href = `#${href}`; if (!href.startsWith('#')) href = `#${href}`;
return href; return href;
} }

View file

@ -1,16 +1,16 @@
import { html, css, LitElement } from "lit"; import formatDateTime from '@utils/formatDateTime';
import { property, customElement } from "lit/decorators.js"; import { LitElement, css, html } from 'lit';
import formatDateTime from "@utils/formatDateTime"; import { customElement, property } from 'lit/decorators.js';
import "@components/MarkdownContent"; import '@components/MarkdownContent';
@customElement("arx-forum-post") @customElement('arx-forum-post')
export class ForumPost extends LitElement { export class ForumPost extends LitElement {
@property({ type: String }) override id = ""; @property({ type: String }) override id = '';
@property({ type: String }) topicId = ""; @property({ type: String }) topicId = '';
@property({ type: String }) npub = ""; @property({ type: String }) npub = '';
@property({ type: Date }) date = new Date(); @property({ type: Date }) date = new Date();
@property({ type: String }) content = ""; @property({ type: String }) content = '';
static override styles = [ static override styles = [
css` css`
@ -82,13 +82,13 @@ export class ForumPost extends LitElement {
</div> </div>
<div> <div>
<arx-markdown-content <arx-markdown-content
.content=${this.content || "no content"} .content=${this.content || 'no content'}
></arx-markdown-content> ></arx-markdown-content>
</div> </div>
<div> <div>
<arx-phora-button <arx-phora-button
href="#" href="#"
@click=${() => alert("TODO")} @click=${() => alert('TODO')}
class="disabled" class="disabled"
> >
<iconify-icon size="32" icon="mdi:reply"></iconify-icon> <iconify-icon size="32" icon="mdi:reply"></iconify-icon>
@ -100,7 +100,7 @@ export class ForumPost extends LitElement {
</arx-phora-button> </arx-phora-button>
<arx-phora-button <arx-phora-button
href="#" href="#"
@click=${() => alert("TODO")} @click=${() => alert('TODO')}
class="disabled" class="disabled"
> >
<iconify-icon size="32" icon="bxs:zap"></iconify-icon> <iconify-icon size="32" icon="bxs:zap"></iconify-icon>
@ -108,7 +108,7 @@ export class ForumPost extends LitElement {
</arx-phora-button> </arx-phora-button>
<arx-phora-button <arx-phora-button
href="#" href="#"
@click=${() => alert("TODO")} @click=${() => alert('TODO')}
class="disabled" class="disabled"
> >
<iconify-icon <iconify-icon

View file

@ -1,15 +1,15 @@
import { html, css, LitElement } from "lit"; import { LitElement, css, html } from 'lit';
import { property, customElement } from "lit/decorators.js"; import { customElement, property } from 'lit/decorators.js';
@customElement("arx-header") @customElement('arx-header')
export class Header extends LitElement { export class Header extends LitElement {
@property({ type: String }) override title = "Eve"; @property({ type: String }) override title = 'Eve';
@property({ type: String }) url = "eve://home"; @property({ type: String }) url = 'eve://home';
@property({ type: Boolean }) canGoBack = false; @property({ type: Boolean }) canGoBack = false;
@property({ type: Boolean }) canGoForward = false; @property({ type: Boolean }) canGoForward = false;
private searchQuery = ""; private searchQuery = '';
private searchInput: HTMLInputElement | null = null; private searchInput: HTMLInputElement | null = null;
static override styles = [ static override styles = [
@ -95,15 +95,15 @@ export class Header extends LitElement {
<header> <header>
<div class="nav-buttons"> <div class="nav-buttons">
<button <button
class=${this.canGoBack ? "" : "disabled"} class=${this.canGoBack ? '' : 'disabled'}
@click=${() => this.dispatchEvent(new CustomEvent("go-back"))} @click=${() => this.dispatchEvent(new CustomEvent('go-back'))}
aria-label="Go back" aria-label="Go back"
> >
<iconify-icon icon="material-symbols:arrow-back"></iconify-icon> <iconify-icon icon="material-symbols:arrow-back"></iconify-icon>
</button> </button>
<button <button
class=${this.canGoForward ? "" : "disabled"} class=${this.canGoForward ? '' : 'disabled'}
@click=${() => this.dispatchEvent(new CustomEvent("go-forward"))} @click=${() => this.dispatchEvent(new CustomEvent('go-forward'))}
aria-label="Go forward" aria-label="Go forward"
> >
<iconify-icon icon="material-symbols:arrow-forward"></iconify-icon> <iconify-icon icon="material-symbols:arrow-forward"></iconify-icon>
@ -126,8 +126,8 @@ export class Header extends LitElement {
} }
private handleSearch(e: KeyboardEvent) { private handleSearch(e: KeyboardEvent) {
if (e.key !== "Enter") return; if (e.key !== 'Enter') return;
const hash = (e.target as HTMLInputElement).value.replace("eve://", "#"); const hash = (e.target as HTMLInputElement).value.replace('eve://', '#');
window.location.hash = hash; window.location.hash = hash;
} }
} }

View file

@ -1,29 +1,29 @@
import { LitElement, html, css } from "lit"; import { ndk, setSigner } from '@/ndk';
import { customElement, state } from "lit/decorators.js"; import { animate } from '@lit-labs/motion';
import { animate } from "@lit-labs/motion"; import { randomBytes } from '@noble/ciphers/webcrypto';
import * as nostrTools from "@nostr/tools/pure"; import { NDKEvent, NDKKind, NDKPrivateKeySigner } from '@nostr-dev-kit/ndk';
import * as nip06 from "@nostr/tools/nip06"; import * as nip06 from '@nostr/tools/nip06';
import * as nip19 from "@nostr/tools/nip19"; import * as nip19 from '@nostr/tools/nip19';
import * as nip49 from "@nostr/tools/nip49"; import * as nip49 from '@nostr/tools/nip49';
import { ndk, setSigner } from "@/ndk"; import * as nostrTools from '@nostr/tools/pure';
import { NDKEvent, NDKKind, NDKPrivateKeySigner } from "@nostr-dev-kit/ndk"; import { encodeBase64 } from '@std/encoding/base64';
import { encodeBase64 } from "@std/encoding/base64"; import { LitElement, css, html } from 'lit';
import { randomBytes } from "@noble/ciphers/webcrypto"; import { customElement, state } from 'lit/decorators.js';
@customElement("arx-initial-setup") @customElement('arx-initial-setup')
export class InitialSetup extends LitElement { export class InitialSetup extends LitElement {
@state() private currentPage = 1; @state() private currentPage = 1;
@state() private isAnimating = false; @state() private isAnimating = false;
@state() private seedPhrase = ""; @state() private seedPhrase = '';
@state() private userName = ""; @state() private userName = '';
@state() private profileImage = ""; @state() private profileImage = '';
@state() private lightningAddress = ""; @state() private lightningAddress = '';
get encryptionPassphrase() { get encryptionPassphrase() {
let encryptionPassphrase = localStorage.getItem("encryption_key"); let encryptionPassphrase = localStorage.getItem('encryption_key');
if (!encryptionPassphrase) { if (!encryptionPassphrase) {
encryptionPassphrase = encodeBase64(randomBytes(32)); encryptionPassphrase = encodeBase64(randomBytes(32));
localStorage.setItem("encryption_key", encryptionPassphrase); localStorage.setItem('encryption_key', encryptionPassphrase);
} }
return encryptionPassphrase; return encryptionPassphrase;
} }
@ -285,7 +285,9 @@ export class InitialSetup extends LitElement {
if (this.isAnimating) return; if (this.isAnimating) return;
this.isAnimating = true; this.isAnimating = true;
this.currentPage = page; this.currentPage = page;
setTimeout(() => (this.isAnimating = false), 300); setTimeout(() => {
this.isAnimating = false;
}, 300);
} }
private onSeedPhraseInput(event: Event) { private onSeedPhraseInput(event: Event) {
@ -297,9 +299,9 @@ export class InitialSetup extends LitElement {
} }
private isValidSeedPhrase() { private isValidSeedPhrase() {
const words = this.seedPhrase.split(" "); const words = this.seedPhrase.split(' ');
if (words.length !== 12) return false; if (words.length !== 12) return false;
if (!nip06.validateWords(words.join(" "))) return false; if (!nip06.validateWords(words.join(' '))) return false;
return true; return true;
} }
@ -574,15 +576,12 @@ export class InitialSetup extends LitElement {
private async goToFinalStep() { private async goToFinalStep() {
const randomPrivateKey = nostrTools.generateSecretKey(); const randomPrivateKey = nostrTools.generateSecretKey();
const encryptedNsec = nip49.encrypt( const encryptedNsec = nip49.encrypt(randomPrivateKey, this.encryptionPassphrase);
randomPrivateKey,
this.encryptionPassphrase
);
const npub = nip19.npubEncode(nostrTools.getPublicKey(randomPrivateKey)); const npub = nip19.npubEncode(nostrTools.getPublicKey(randomPrivateKey));
if (!this.lightningAddress) this.lightningAddress = `${npub}@npub.cash`; if (!this.lightningAddress) this.lightningAddress = `${npub}@npub.cash`;
localStorage.setItem("ncryptsec", encryptedNsec); localStorage.setItem('ncryptsec', encryptedNsec);
setSigner(new NDKPrivateKeySigner(randomPrivateKey)); setSigner(new NDKPrivateKeySigner(randomPrivateKey));
await ndk.connect(5000); await ndk.connect(5000);
@ -615,11 +614,13 @@ export class InitialSetup extends LitElement {
required to invite new members to the community. required to invite new members to the community.
</p> </p>
<p>Your username is: <b>${this.userName}</b></p> <p>Your username is: <b>${this.userName}</b></p>
${this.profileImage ${
? html` <p> this.profileImage
? html` <p>
Your profile image is: <img .src=${this.profileImage} /> Your profile image is: <img .src=${this.profileImage} />
</p>` </p>`
: ""} : ''
}
<p>Your lightning address is: <b>${this.lightningAddress}</b></p> <p>Your lightning address is: <b>${this.lightningAddress}</b></p>
</section> </section>
@ -638,7 +639,7 @@ export class InitialSetup extends LitElement {
finish() { finish() {
this.dispatchEvent( this.dispatchEvent(
new CustomEvent("finish", { new CustomEvent('finish', {
detail: { detail: {
userName: this.userName, userName: this.userName,
profileImage: this.profileImage, profileImage: this.profileImage,
@ -646,7 +647,7 @@ export class InitialSetup extends LitElement {
}, },
bubbles: true, bubbles: true,
composed: true, composed: true,
}) }),
); );
} }

View file

@ -1,4 +1,4 @@
import { html, LitElement } from 'lit'; import { LitElement, html } from 'lit';
import { customElement } from 'lit/decorators.js'; import { customElement } from 'lit/decorators.js';
@customElement('arx-loading-view') @customElement('arx-loading-view')

View file

@ -1,18 +1,18 @@
import { css, LitElement } from "lit"; import { LitElement, css } from 'lit';
import { customElement, property } from "lit/decorators.js"; import { customElement, property } from 'lit/decorators.js';
import { unsafeHTML } from "lit/directives/unsafe-html.js"; import { unsafeHTML } from 'lit/directives/unsafe-html.js';
import MarkdownIt, { type StateCore, type Token } from "markdown-it"; import MarkdownIt, { type StateCore, type Token } from 'markdown-it';
function nostrPlugin(md: MarkdownIt): void { function nostrPlugin(md: MarkdownIt): void {
const npubRegex = /(npub[0-9a-zA-Z]{59})/g; const npubRegex = /(npub[0-9a-zA-Z]{59})/g;
md.core.ruler.after("inline", "nostr_npub", (state: StateCore): boolean => { md.core.ruler.after('inline', 'nostr_npub', (state: StateCore): boolean => {
for (const token of state.tokens) { for (const token of state.tokens) {
if (token.type === "inline" && token.children) { if (token.type === 'inline' && token.children) {
for (let i = 0; i < token.children.length; i++) { for (let i = 0; i < token.children.length; i++) {
const child = token.children[i]; const child = token.children[i];
if (child.type === "text") { if (child.type === 'text') {
const matches = child.content.match(npubRegex); const matches = child.content.match(npubRegex);
if (!matches) continue; if (!matches) continue;
@ -24,26 +24,26 @@ function nostrPlugin(md: MarkdownIt): void {
// @ts-ignore this is an issue with the types // @ts-ignore this is an issue with the types
(match: string, npub: string, offset: number) => { (match: string, npub: string, offset: number) => {
if (offset > lastIndex) { if (offset > lastIndex) {
const textToken = new state.Token("text", "", 0); const textToken = new state.Token('text', '', 0);
textToken.content = child.content.slice(lastIndex, offset); textToken.content = child.content.slice(lastIndex, offset);
newTokens.push(textToken); newTokens.push(textToken);
} }
const linkOpen = new state.Token("link_open", "a", 1); const linkOpen = new state.Token('link_open', 'a', 1);
linkOpen.attrs = [["href", `nostr:${npub}`]]; linkOpen.attrs = [['href', `nostr:${npub}`]];
const text = new state.Token("text", "", 0); const text = new state.Token('text', '', 0);
text.content = npub; text.content = npub;
const linkClose = new state.Token("link_close", "a", -1); const linkClose = new state.Token('link_close', 'a', -1);
newTokens.push(linkOpen, text, linkClose); newTokens.push(linkOpen, text, linkClose);
lastIndex = offset + match.length; lastIndex = offset + match.length;
} },
); );
if (lastIndex < child.content.length) { if (lastIndex < child.content.length) {
const textToken = new state.Token("text", "", 0); const textToken = new state.Token('text', '', 0);
textToken.content = child.content.slice(lastIndex); textToken.content = child.content.slice(lastIndex);
newTokens.push(textToken); newTokens.push(textToken);
} }
@ -59,7 +59,7 @@ function nostrPlugin(md: MarkdownIt): void {
}); });
} }
@customElement("arx-markdown-content") @customElement('arx-markdown-content')
export class MarkdownContent extends LitElement { export class MarkdownContent extends LitElement {
private md = new MarkdownIt({ private md = new MarkdownIt({
html: false, html: false,
@ -69,7 +69,7 @@ export class MarkdownContent extends LitElement {
}); });
@property({ type: String }) @property({ type: String })
content = ""; content = '';
static override styles = [ static override styles = [
css` css`

View file

@ -1,5 +1,5 @@
import type { NDKUserProfile } from '@nostr-dev-kit/ndk'; import type { NDKUserProfile } from '@nostr-dev-kit/ndk';
import { css, html, LitElement } from 'lit-element'; import { LitElement, css, html } from 'lit-element';
import { customElement, property } from 'lit/decorators.js'; import { customElement, property } from 'lit/decorators.js';
type AvatarSize = 'short' | 'medium' | 'large' | 'huge'; type AvatarSize = 'short' | 'medium' | 'large' | 'huge';

View file

@ -1,6 +1,6 @@
import { html, css, LitElement } from 'lit';
import { property, customElement, state } from 'lit/decorators.js';
import type { NDKUserProfile } from '@nostr-dev-kit/ndk'; import type { NDKUserProfile } from '@nostr-dev-kit/ndk';
import { LitElement, css, html } from 'lit';
import { customElement, property, state } from 'lit/decorators.js';
import { getUserProfile } from '../ndk'; import { getUserProfile } from '../ndk';
import '@components/profiles/ShortProfile'; import '@components/profiles/ShortProfile';
import '@components/profiles/MediumProfile'; import '@components/profiles/MediumProfile';
@ -11,11 +11,7 @@ import '@components/profiles/CardProfile';
export class NostrProfile extends LitElement { export class NostrProfile extends LitElement {
@property() npub = ''; @property() npub = '';
@property({ reflect: true }) renderType: @property({ reflect: true }) renderType: 'short' | 'medium' | 'large' | 'card' = 'short';
| 'short'
| 'medium'
| 'large'
| 'card' = 'short';
@state() @state()
private profile: NDKUserProfile | undefined = undefined; private profile: NDKUserProfile | undefined = undefined;

View file

@ -1,17 +1,17 @@
import { html, css, LitElement } from "lit"; import { LitElement, css, html } from 'lit';
import { property, customElement } from "lit/decorators.js"; import { customElement, property } from 'lit/decorators.js';
import "@components/EveLink"; import '@components/EveLink';
@customElement("arx-phora-button") @customElement('arx-phora-button')
export class PhoraButton extends LitElement { export class PhoraButton extends LitElement {
@property({ type: String }) href = ""; @property({ type: String }) href = '';
@property({ type: String }) target = ""; @property({ type: String }) target = '';
@property({ type: String }) rel = ""; @property({ type: String }) rel = '';
@property({ type: Boolean }) disabled = false; @property({ type: Boolean }) disabled = false;
get hrefValue() { get hrefValue() {
if (!this.href || this.disabled) return "javascript:void(0)"; if (!this.href || this.disabled) return 'javascript:void(0)';
return this.href; return this.href;
} }
@ -66,7 +66,7 @@ export class PhoraButton extends LitElement {
.href=${this.hrefValue} .href=${this.hrefValue}
.target=${this.target} .target=${this.target}
.rel=${this.rel} .rel=${this.rel}
class="${this.disabled ? "disabled" : ""}" class="${this.disabled ? 'disabled' : ''}"
> >
<slot></slot> <slot></slot>
</arx-eve-link> </arx-eve-link>

View file

@ -1,10 +1,10 @@
import { html, css, LitElement } from "lit"; import { LitElement, css, html } from 'lit';
import { property, customElement } from "lit/decorators.js"; import { customElement, property } from 'lit/decorators.js';
@customElement("arx-phora-forum-category") @customElement('arx-phora-forum-category')
export class PhoraForumCategory extends LitElement { export class PhoraForumCategory extends LitElement {
@property({ type: String }) override title = ""; @property({ type: String }) override title = '';
@property({ type: String }) override id = ""; @property({ type: String }) override id = '';
static override styles = [ static override styles = [
css` css`

View file

@ -1,9 +1,9 @@
import { html, css, LitElement } from "lit"; import { LitElement, css, html } from 'lit';
import { property, customElement } from "lit/decorators.js"; import { customElement, property } from 'lit/decorators.js';
import "@components/EveLink"; import '@components/EveLink';
@customElement("arx-phora-forum-topic") @customElement('arx-phora-forum-topic')
export class PhoraForumTopic extends LitElement { export class PhoraForumTopic extends LitElement {
static override styles = [ static override styles = [
css` css`
@ -165,19 +165,19 @@ export class PhoraForumTopic extends LitElement {
`, `,
]; ];
@property({ type: String }) override id = ""; @property({ type: String }) override id = '';
@property({ type: String }) override title = ""; @property({ type: String }) override title = '';
@property({ type: String }) description = ""; @property({ type: String }) description = '';
@property({ type: Number }) posts = 0; @property({ type: Number }) posts = 0;
@property({ type: String }) lastPostBy = ""; @property({ type: String }) lastPostBy = '';
@property({ type: String }) lastPostTime = ""; @property({ type: String }) lastPostTime = '';
@property({ type: Boolean }) isNew = false; @property({ type: Boolean }) isNew = false;
@property({ type: Boolean }) isHot = false; @property({ type: Boolean }) isHot = false;
get status() { get status() {
if (this.isNew) return "new-status"; if (this.isNew) return 'new-status';
if (this.isHot) return "hot-status"; if (this.isHot) return 'hot-status';
return ""; return '';
} }
override render() { override render() {

View file

@ -1,8 +1,8 @@
import { html, css, LitElement } from "lit"; import { getLastBlockHeight } from '@utils/lastBlockHeight';
import { customElement, state } from "lit/decorators.js"; import { LitElement, css, html } from 'lit';
import { getLastBlockHeight } from "@utils/lastBlockHeight"; import { customElement, state } from 'lit/decorators.js';
@customElement("arx-bitcoin-block-widget") @customElement('arx-bitcoin-block-widget')
export class BitcoinBlockWidget extends LitElement { export class BitcoinBlockWidget extends LitElement {
@state() @state()
private lastBlock: number | null = null; private lastBlock: number | null = null;
@ -21,10 +21,7 @@ export class BitcoinBlockWidget extends LitElement {
constructor() { constructor() {
super(); super();
this.loadBlockHeight(); this.loadBlockHeight();
this.timer = window.setInterval( this.timer = window.setInterval(this.loadBlockHeight, this.REFRESH_INTERVAL);
this.loadBlockHeight,
this.REFRESH_INTERVAL
);
} }
override disconnectedCallback() { override disconnectedCallback() {
@ -38,7 +35,7 @@ export class BitcoinBlockWidget extends LitElement {
this.lastBlock = response.height; this.lastBlock = response.height;
this.error = null; this.error = null;
} catch (error) { } catch (error) {
this.error = "Failed to load block height"; this.error = 'Failed to load block height';
console.error(error); console.error(error);
} finally { } finally {
this.isLoading = false; this.isLoading = false;

View file

@ -1,7 +1,7 @@
import { html, css, LitElement } from 'lit';
import { property, customElement, state } from 'lit/decorators.js';
import type { NDKUserProfile } from '@nostr-dev-kit/ndk'; import type { NDKUserProfile } from '@nostr-dev-kit/ndk';
import { getProfile } from '@utils/profileUtils'; import { getProfile } from '@utils/profileUtils';
import { LitElement, css, html } from 'lit';
import { customElement, property, state } from 'lit/decorators.js';
@customElement('arx-nostr-card-profile') @customElement('arx-nostr-card-profile')
export class CardProfile extends LitElement { export class CardProfile extends LitElement {
@ -86,7 +86,7 @@ export class CardProfile extends LitElement {
.join('\n') .join('\n')
.trim() .trim()
.split(/-+\n/, 2) .split(/-+\n/, 2)
.filter(section => section.trim() !== '') .filter((section) => section.trim() !== '')
.join('\n') .join('\n')
.trim(); .trim();

View file

@ -1,8 +1,8 @@
import { html, css, LitElement } from 'lit';
import { property, customElement, state } from 'lit/decorators.js';
import type { NDKUserProfile } from '@nostr-dev-kit/ndk'; import type { NDKUserProfile } from '@nostr-dev-kit/ndk';
import { getProfile } from '@utils/profileUtils';
import firstLine from '@utils/firstLine'; import firstLine from '@utils/firstLine';
import { getProfile } from '@utils/profileUtils';
import { LitElement, css, html } from 'lit';
import { customElement, property, state } from 'lit/decorators.js';
@customElement('arx-nostr-large-profile') @customElement('arx-nostr-large-profile')
export class LargeProfile extends LitElement { export class LargeProfile extends LitElement {

View file

@ -1,24 +1,24 @@
import { html, css, LitElement } from "lit"; import type { NDKUserProfile } from '@nostr-dev-kit/ndk';
import { property, customElement, state } from "lit/decorators.js"; import firstLine from '@utils/firstLine';
import type { NDKUserProfile } from "@nostr-dev-kit/ndk"; import { getProfile } from '@utils/profileUtils';
import { getProfile } from "@utils/profileUtils"; import { LitElement, css, html } from 'lit';
import firstLine from "@utils/firstLine"; import { customElement, property, state } from 'lit/decorators.js';
import "@components/EveLink"; import '@components/EveLink';
@customElement("arx-nostr-medium-profile") @customElement('arx-nostr-medium-profile')
export class MediumProfile extends LitElement { export class MediumProfile extends LitElement {
@property() profile!: NDKUserProfile; @property() profile!: NDKUserProfile;
@property() npub = ""; @property() npub = '';
@state() @state()
private displayName = ""; private displayName = '';
@state() @state()
private profileUrl = ""; private profileUrl = '';
@state() @state()
private truncatedAbout = ""; private truncatedAbout = '';
static override styles = [ static override styles = [
css` css`

View file

@ -1,20 +1,20 @@
import { html, css, LitElement } from "lit"; import type { NDKUserProfile } from '@nostr-dev-kit/ndk';
import { property, customElement, state } from "lit/decorators.js"; import { getProfile } from '@utils/profileUtils';
import type { NDKUserProfile } from "@nostr-dev-kit/ndk"; import { LitElement, css, html } from 'lit';
import { getProfile } from "@utils/profileUtils"; import { customElement, property, state } from 'lit/decorators.js';
import "@components/EveLink"; import '@components/EveLink';
@customElement("arx-nostr-short-profile") @customElement('arx-nostr-short-profile')
export class ShortProfile extends LitElement { export class ShortProfile extends LitElement {
@property() profile!: NDKUserProfile; @property() profile!: NDKUserProfile;
@property() npub = ""; @property() npub = '';
@state() @state()
private displayName = ""; private displayName = '';
@state() @state()
private profileUrl = ""; private profileUrl = '';
static override styles = [ static override styles = [
css` css`

View file

@ -1,38 +1,38 @@
import { app, shell, BrowserWindow, ipcMain } from "electron"; import fs from 'node:fs';
import { optimizer, is } from "@electron-toolkit/utils"; import os from 'node:os';
import { RelayManager } from "./relayManager"; import path from 'node:path';
import path from "node:path"; import { is, optimizer } from '@electron-toolkit/utils';
import fs from "node:fs"; import { BrowserWindow, app, ipcMain, shell } from 'electron';
import os from "node:os"; import { RelayManager } from './relayManager';
const relay = new RelayManager(); const relay = new RelayManager();
ipcMain.handle("relay:writeSeed", async (_, ...args: any) => { ipcMain.handle('relay:writeSeed', async (_, ...args: string[]) => {
if (!args[0]) throw new Error("No seed provided"); if (!args[0]) throw new Error('No seed provided');
const seed = args[0] as string; const seed = args[0] as string;
let configPath: string; let configPath: string;
if (process.platform === "darwin") { if (process.platform === 'darwin') {
configPath = path.join(app.getPath("userData"), "arx", "Eve"); configPath = path.join(app.getPath('userData'), 'arx', 'Eve');
} else { } else {
configPath = path.join(os.homedir(), ".config", "arx", "Eve"); configPath = path.join(os.homedir(), '.config', 'arx', 'Eve');
} }
const seedPath = path.join(configPath, "ccn.seed"); const seedPath = path.join(configPath, 'ccn.seed');
fs.mkdirSync(configPath, { recursive: true }); fs.mkdirSync(configPath, { recursive: true });
fs.writeFileSync(seedPath, seed); fs.writeFileSync(seedPath, seed);
}); });
ipcMain.handle("relay:start", (_, ...args: any) => { ipcMain.handle('relay:start', (_, ...args: string[]) => {
if (!args[0]) throw new Error("No encryption key provided"); if (!args[0]) throw new Error('No encryption key provided');
const encryptionKey = args[0] as string; const encryptionKey = args[0];
return relay.start(encryptionKey); return relay.start(encryptionKey);
}); });
ipcMain.handle("relay:stop", () => { ipcMain.handle('relay:stop', () => {
return relay.stop(); return relay.stop();
}); });
ipcMain.handle("relay:status", () => { ipcMain.handle('relay:status', () => {
return { return {
running: relay.isRunning, running: relay.isRunning,
pid: relay.pid, pid: relay.pid,
@ -40,7 +40,7 @@ ipcMain.handle("relay:status", () => {
}; };
}); });
ipcMain.handle("relay:getLogs", () => { ipcMain.handle('relay:getLogs', () => {
return relay.getLogs(); return relay.getLogs();
}); });
@ -51,33 +51,32 @@ function createWindow(): void {
show: false, show: false,
autoHideMenuBar: true, autoHideMenuBar: true,
webPreferences: { webPreferences: {
preload: path.join(__dirname, "../preload/preload.mjs"), preload: path.join(__dirname, '../preload/preload.mjs'),
sandbox: false, sandbox: false,
}, },
}); });
mainWindow.on("ready-to-show", () => { mainWindow.on('ready-to-show', () => {
mainWindow.show(); mainWindow.show();
}); });
mainWindow.webContents.setWindowOpenHandler((details) => { mainWindow.webContents.setWindowOpenHandler((details) => {
shell.openExternal(details.url); shell.openExternal(details.url);
return { action: "deny" }; return { action: 'deny' };
}); });
if (is.dev && process.env["ELECTRON_RENDERER_URL"]) if (is.dev && process.env['ELECTRON_RENDERER_URL']) mainWindow.loadURL(process.env['ELECTRON_RENDERER_URL']);
mainWindow.loadURL(process.env["ELECTRON_RENDERER_URL"]); else mainWindow.loadFile(path.join(__dirname, '../renderer/index.html'));
else mainWindow.loadFile(path.join(__dirname, "../renderer/index.html"));
} }
app.whenReady().then(() => { app.whenReady().then(() => {
app.on("browser-window-created", (_, window) => { app.on('browser-window-created', (_, window) => {
optimizer.watchWindowShortcuts(window); optimizer.watchWindowShortcuts(window);
}); });
createWindow(); createWindow();
}); });
app.on("window-all-closed", () => { app.on('window-all-closed', () => {
app.quit(); app.quit();
}); });

View file

@ -1,16 +1,15 @@
import { contextBridge, ipcRenderer } from "electron"; import { electronAPI } from '@electron-toolkit/preload';
import { electronAPI } from "@electron-toolkit/preload"; import { contextBridge, ipcRenderer } from 'electron';
if (process.contextIsolated) { if (process.contextIsolated) {
try { try {
contextBridge.exposeInMainWorld("electron", electronAPI); contextBridge.exposeInMainWorld('electron', electronAPI);
contextBridge.exposeInMainWorld("relay", { contextBridge.exposeInMainWorld('relay', {
writeSeed: (seed: string) => ipcRenderer.invoke("relay:writeSeed", seed), writeSeed: (seed: string) => ipcRenderer.invoke('relay:writeSeed', seed),
start: (encryptionKey: string) => start: (encryptionKey: string) => ipcRenderer.invoke('relay:start', encryptionKey),
ipcRenderer.invoke("relay:start", encryptionKey), stop: () => ipcRenderer.invoke('relay:stop'),
stop: () => ipcRenderer.invoke("relay:stop"), getStatus: () => ipcRenderer.invoke('relay:status'),
getStatus: () => ipcRenderer.invoke("relay:status"), getLogs: () => ipcRenderer.invoke('relay:logs'),
getLogs: () => ipcRenderer.invoke("relay:logs"),
}); });
} catch (error) { } catch (error) {
console.error(error); console.error(error);

View file

@ -1,8 +1,8 @@
import { spawn, ChildProcess } from "child_process"; import { type ChildProcess, spawn } from 'node:child_process';
import { join } from "path"; import { join } from 'node:path';
import { is } from "@electron-toolkit/utils"; import { is } from '@electron-toolkit/utils';
type PackageEnvironment = "flatpak" | "appimage" | "system" | "mac" | "dev"; type PackageEnvironment = 'flatpak' | 'appimage' | 'system' | 'mac' | 'dev';
export class RelayManager { export class RelayManager {
private process: ChildProcess | null; private process: ChildProcess | null;
@ -49,27 +49,27 @@ export class RelayManager {
} }
private detectEnvironment(): PackageEnvironment { private detectEnvironment(): PackageEnvironment {
if (is.dev) return "dev"; if (is.dev) return 'dev';
if (process.platform === "darwin") return "mac"; if (process.platform === 'darwin') return 'mac';
if (process.env.FLATPAK_ID) return "flatpak"; if (process.env.FLATPAK_ID) return 'flatpak';
if (process.env.APPIMAGE) return "appimage"; if (process.env.APPIMAGE) return 'appimage';
return "system"; return 'system';
} }
private getRelayPath(): string { private getRelayPath(): string {
const environment = this.detectEnvironment(); const environment = this.detectEnvironment();
switch (environment) { switch (environment) {
case "dev": case 'dev':
return join(__dirname, "../../extras/linux/relay"); return join(__dirname, '../../extras/linux/relay');
case "mac": case 'mac':
return join(process.resourcesPath, "macos", "eve-relay"); return join(process.resourcesPath, 'macos', 'eve-relay');
case "flatpak": case 'flatpak':
return "/app/lib/com.arx_ccn.eve/usr/bin/eve-relay"; return '/app/lib/com.arx_ccn.eve/usr/bin/eve-relay';
case "appimage": case 'appimage':
return join(process.env.APPDIR || "", "usr/bin/eve-relay"); return join(process.env.APPDIR || '', 'usr/bin/eve-relay');
case "system": case 'system':
return "/usr/bin/eve-relay"; return '/usr/bin/eve-relay';
} }
} }
@ -82,16 +82,12 @@ export class RelayManager {
private restartProcess(): void { private restartProcess(): void {
if (this.restartAttempts >= this.maxRestartAttempts) { if (this.restartAttempts >= this.maxRestartAttempts) {
console.error( console.error(`Failed to restart relay after ${this.maxRestartAttempts} attempts`);
`Failed to restart relay after ${this.maxRestartAttempts} attempts`
);
return; return;
} }
this.restartAttempts++; this.restartAttempts++;
console.log( console.log(`Attempting restart #${this.restartAttempts} in ${this.restartDelay}ms...`);
`Attempting restart #${this.restartAttempts} in ${this.restartDelay}ms...`
);
if (this.restartTimeout) clearTimeout(this.restartTimeout); if (this.restartTimeout) clearTimeout(this.restartTimeout);
@ -137,7 +133,7 @@ export class RelayManager {
}); });
if (this.process.stdout) { if (this.process.stdout) {
this.process.stdout.on("data", (data: Buffer) => { this.process.stdout.on('data', (data: Buffer) => {
const logLine = data.toString().trim(); const logLine = data.toString().trim();
this.addLog(logLine); this.addLog(logLine);
console.log(logLine); console.log(logLine);
@ -145,30 +141,26 @@ export class RelayManager {
} }
if (this.process.stderr) { if (this.process.stderr) {
this.process.stderr.on("data", (data: Buffer) => { this.process.stderr.on('data', (data: Buffer) => {
const logLine = data.toString().trim(); const logLine = data.toString().trim();
this.addLog(logLine); this.addLog(logLine);
console.error(logLine); console.error(logLine);
}); });
} }
this.process.on("error", (err: Error) => { this.process.on('error', (err: Error) => {
console.error(`Failed to start Relay: ${err.message}`); console.error(`Failed to start Relay: ${err.message}`);
this.process = null; this.process = null;
this.restartProcess(); this.restartProcess();
}); });
this.process.on("exit", this.handleProcessExit.bind(this)); this.process.on('exit', this.handleProcessExit.bind(this));
if (this.process.pid) { if (this.process.pid) {
this.restartAttempts = 0; this.restartAttempts = 0;
} }
} catch (error) { } catch (error) {
console.error( console.error(`Error starting Relay: ${error instanceof Error ? error.message : 'Unknown error'}`);
`Error starting Relay: ${
error instanceof Error ? error.message : "Unknown error"
}`
);
this.restartProcess(); this.restartProcess();
} }
} }

View file

@ -1,28 +1,28 @@
import "./style.scss"; import './style.scss';
import "@components/ErrorView"; import '@components/ErrorView';
import "@components/NostrAvatar"; import '@components/NostrAvatar';
import "@components/LoadingView"; import '@components/LoadingView';
import "@components/NostrProfile"; import '@components/NostrProfile';
import "@components/Breadcrumbs"; import '@components/Breadcrumbs';
import "@components/Header"; import '@components/Header';
import "@routes/router"; import '@routes/router';
import "@components/LoadingView"; import '@components/LoadingView';
import type EveRouter from "@routes/router"; import type EveRouter from '@routes/router';
import { sleep } from "./utils/sleep"; import { sleep } from './utils/sleep';
async function startRelay() { async function startRelay() {
if (localStorage.getItem("ncryptsec")) { if (localStorage.getItem('ncryptsec')) {
const loadingIndicator = document.createElement("arx-loading-view"); const loadingIndicator = document.createElement('arx-loading-view');
document.body.appendChild(loadingIndicator); document.body.appendChild(loadingIndicator);
await window.relay.start(localStorage.getItem("encryption_key")!); await window.relay.start(localStorage.getItem('encryption_key')!);
await sleep(5000); await sleep(5000);
loadingIndicator.remove(); loadingIndicator.remove();
} }
} }
startRelay().then(() => { startRelay().then(() => {
const router = document.createElement("arx-eve-router") as EveRouter; const router = document.createElement('arx-eve-router') as EveRouter;
router.ccnSetup = !!localStorage.getItem("ncryptsec"); router.ccnSetup = !!localStorage.getItem('ncryptsec');
document.body.appendChild(router); document.body.appendChild(router);
}); });

View file

@ -1,22 +1,20 @@
import NDK, { NDKPrivateKeySigner } from "@nostr-dev-kit/ndk"; import NDK, { NDKPrivateKeySigner } from '@nostr-dev-kit/ndk';
import * as nip49 from "@nostr/tools/nip49"; import * as nip49 from '@nostr/tools/nip49';
export const ndk = new NDK({ export const ndk = new NDK({
explicitRelayUrls: ["ws://localhost:6942"], explicitRelayUrls: ['ws://localhost:6942'],
enableOutboxModel: false, enableOutboxModel: false,
autoConnectUserRelays: false, autoConnectUserRelays: false,
clientName: "Arx", clientName: 'Arx',
clientNip89: "arx", clientNip89: 'arx',
}); });
export async function getSigner() { export async function getSigner() {
await ndk.connect(); await ndk.connect();
if (ndk.signer) return; if (ndk.signer) return;
const encryptionPassphrase = localStorage.getItem("encryption_key"); const encryptionPassphrase = localStorage.getItem('encryption_key');
if (!encryptionPassphrase) throw new Error("Encryption passphrase not found"); if (!encryptionPassphrase) throw new Error('Encryption passphrase not found');
const signer = new NDKPrivateKeySigner( const signer = new NDKPrivateKeySigner(nip49.decrypt(localStorage.getItem('ncryptsec')!, encryptionPassphrase));
nip49.decrypt(localStorage.getItem("ncryptsec")!, encryptionPassphrase)
);
setSigner(signer); setSigner(signer);
} }
@ -24,7 +22,7 @@ export async function getNpub() {
await getSigner(); await getSigner();
const user = await ndk.signer?.user(); const user = await ndk.signer?.user();
if (user) return user.npub; if (user) return user.npub;
throw new Error("Could not get npub"); throw new Error('Could not get npub');
} }
export function setSigner(signer: NDKPrivateKeySigner) { export function setSigner(signer: NDKPrivateKeySigner) {
@ -33,7 +31,7 @@ export function setSigner(signer: NDKPrivateKeySigner) {
export async function getUserProfile(npub: string) { export async function getUserProfile(npub: string) {
await ndk.connect(); await ndk.connect();
const query = npub.startsWith("npub") ? { npub } : { pubkey: npub }; const query = npub.startsWith('npub') ? { npub } : { pubkey: npub };
const user = ndk.getUser(query); const user = ndk.getUser(query);
await user.fetchProfile(); await user.fetchProfile();
return user.profile; return user.profile;

View file

@ -1,16 +1,16 @@
import { html, css, LitElement } from "lit"; import { LitElement, css, html } from 'lit';
import { customElement, property } from "lit/decorators.js"; import { customElement, property } from 'lit/decorators.js';
import type { RouteParams } from "./router"; import type { RouteParams } from './router';
import "@components/EveLink"; import '@components/EveLink';
@customElement("arx-404-page") @customElement('arx-404-page')
export class FourOhFourPage extends LitElement { export class FourOhFourPage extends LitElement {
@property({ type: Object }) @property({ type: Object })
params: RouteParams = {}; params: RouteParams = {};
@property({ type: String }) @property({ type: String })
path = ""; path = '';
@property({ type: Boolean }) @property({ type: Boolean })
canGoBack = false; canGoBack = false;
@ -177,10 +177,10 @@ export class FourOhFourPage extends LitElement {
href="javascript:void(0)" href="javascript:void(0)"
@click="${() => @click="${() =>
this.dispatchEvent( this.dispatchEvent(
new CustomEvent("go-back", { new CustomEvent('go-back', {
bubbles: true, bubbles: true,
composed: true, composed: true,
}) }),
)}" )}"
class="primary-button" class="primary-button"
> >

View file

@ -1,12 +1,12 @@
import { getNpub, getUserProfile } from "@/ndk"; import { getNpub, getUserProfile } from '@/ndk';
import type { NDKUserProfile } from "@nostr-dev-kit/ndk"; import type { NDKUserProfile } from '@nostr-dev-kit/ndk';
import { css, LitElement } from "lit"; import { LitElement, css } from 'lit';
import { customElement, state } from "lit/decorators.js"; import { customElement, state } from 'lit/decorators.js';
import { html, literal } from "lit/static-html.js"; import { html, literal } from 'lit/static-html.js';
import "@widgets/BitcoinBlockWidget"; import '@widgets/BitcoinBlockWidget';
import "@components/AppGrid"; import '@components/AppGrid';
@customElement("arx-eve-home") @customElement('arx-eve-home')
export class Home extends LitElement { export class Home extends LitElement {
@state() @state()
private npub: string | undefined; private npub: string | undefined;
@ -18,72 +18,72 @@ export class Home extends LitElement {
apps = [ apps = [
{ {
id: 0, id: 0,
href: "letters", href: 'letters',
name: "Letters", name: 'Letters',
color: "#FF33BB", color: '#FF33BB',
icon: "bxs:envelope", icon: 'bxs:envelope',
}, },
{ {
id: 1, id: 1,
href: "messages", href: 'messages',
name: "Messages", name: 'Messages',
color: "#34C759", color: '#34C759',
icon: "bxs:chat", icon: 'bxs:chat',
}, },
{ {
id: 2, id: 2,
href: "calendar", href: 'calendar',
name: "Calendar", name: 'Calendar',
color: "#FF9500", color: '#FF9500',
icon: "bxs:calendar", icon: 'bxs:calendar',
}, },
{ {
id: 3, id: 3,
href: "phora", href: 'phora',
name: "Phora", name: 'Phora',
color: "#FF3B30", color: '#FF3B30',
icon: "bxs:conversation", icon: 'bxs:conversation',
}, },
{ {
id: 5, id: 5,
href: "agora", href: 'agora',
name: "Agora", name: 'Agora',
color: "#5856D6", color: '#5856D6',
icon: "bxs:store", icon: 'bxs:store',
}, },
{ {
id: 6, id: 6,
href: "wallet", href: 'wallet',
name: "Wallet", name: 'Wallet',
color: "#007AFF", color: '#007AFF',
icon: "bxs:wallet", icon: 'bxs:wallet',
}, },
{ {
id: 7, id: 7,
href: "consortium", href: 'consortium',
name: "Consortium", name: 'Consortium',
color: "#FFCC00", color: '#FFCC00',
icon: "bxs:landmark", icon: 'bxs:landmark',
}, },
{ {
id: 8, id: 8,
href: "settings", href: 'settings',
name: "Settings", name: 'Settings',
color: "#deadbeef", color: '#deadbeef',
icon: "bxs:wrench", icon: 'bxs:wrench',
}, },
]; ];
widgets = [ widgets = [
{ {
title: "Bitcoin Block", title: 'Bitcoin Block',
content: literal`arx-bitcoin-block-widget`, content: literal`arx-bitcoin-block-widget`,
}, },
]; ];
async loadProperties() { async loadProperties() {
const npub = await getNpub(); const npub = await getNpub();
if (!npub) return alert("No npub?"); if (!npub) return alert('No npub?');
this.npub = npub; this.npub = npub;
this.profile = (await getUserProfile(this.npub)) as NDKUserProfile; this.profile = (await getUserProfile(this.npub)) as NDKUserProfile;
this.username = this.profile?.name || this.npub.substring(0, 8); this.username = this.profile?.name || this.npub.substring(0, 8);
@ -242,7 +242,7 @@ export class Home extends LitElement {
<h3>${widget.title}</h3> <h3>${widget.title}</h3>
<${widget.content}></${widget.content}> <${widget.content}></${widget.content}>
</div> </div>
` `,
)} )}
</div> </div>
</div> </div>

View file

@ -1,13 +1,13 @@
import { LitElement, html, css } from "lit"; import { getSigner, ndk } from '@/ndk';
import { customElement, state } from "lit/decorators.js"; import type { NDKSubscription } from '@nostr-dev-kit/ndk';
import { getSigner, ndk } from "@/ndk"; import formatDateTime from '@utils/formatDateTime';
import formatDateTime from "@utils/formatDateTime"; import { LitElement, css, html } from 'lit';
import type { NDKSubscription } from "@nostr-dev-kit/ndk"; import { customElement, state } from 'lit/decorators.js';
import "@components/Breadcrumbs"; import '@components/Breadcrumbs';
import "@components/PhoraForumCategory"; import '@components/PhoraForumCategory';
import "@components/PhoraForumTopic"; import '@components/PhoraForumTopic';
import "@components/PhoraButton"; import '@components/PhoraButton';
interface ForumTopic { interface ForumTopic {
id: string; id: string;
@ -24,7 +24,7 @@ interface ForumCategory {
topics: ForumTopic[]; topics: ForumTopic[];
} }
@customElement("arx-phora-home") @customElement('arx-phora-home')
export class PhoraForum extends LitElement { export class PhoraForum extends LitElement {
@state() @state()
private categories: ForumCategory[] = []; private categories: ForumCategory[] = [];
@ -53,18 +53,14 @@ export class PhoraForum extends LitElement {
.subscribe({ .subscribe({
kinds: [11], kinds: [11],
}) })
.on("event", (event) => { .on('event', (event) => {
const subject = event.tags.find( const subject = event.tags.find((tag: string[]) => tag[0] === 'subject');
(tag: string[]) => tag[0] === "subject" const parent = event.tags.find((tag: string[]) => tag[0] === 'e');
);
const parent = event.tags.find((tag: string[]) => tag[0] === "e");
if (!subject) return; if (!subject) return;
if (parent) { if (parent) {
const categoryIndex = this.categories.findIndex( const categoryIndex = this.categories.findIndex((category) => category.id === parent[1]);
(category) => category.id === parent[1]
);
if (categoryIndex === -1) return; if (categoryIndex === -1) return;
const updatedCategories = [...this.categories]; const updatedCategories = [...this.categories];
@ -95,7 +91,7 @@ export class PhoraForum extends LitElement {
override render() { override render() {
return html` return html`
<arx-breadcrumbs <arx-breadcrumbs
.items=${[{ text: "Home", href: "/" }, { text: "Phora" }]} .items=${[{ text: 'Home', href: '/' }, { text: 'Phora' }]}
> >
</arx-breadcrumbs> </arx-breadcrumbs>
@ -116,10 +112,10 @@ export class PhoraForum extends LitElement {
lastPostTime=${topic.created_at} lastPostTime=${topic.created_at}
> >
</arx-phora-forum-topic> </arx-phora-forum-topic>
` `,
)} )}
</arx-phora-forum-category> </arx-phora-forum-category>
` `,
)} )}
`; `;
} }

View file

@ -1,15 +1,15 @@
import { LitElement, html, css } from "lit"; import { getSigner, ndk } from '@/ndk';
import { customElement, state } from "lit/decorators.js"; import { NDKEvent } from '@nostr-dev-kit/ndk';
import { getSigner, ndk } from "@/ndk"; import { LitElement, css, html } from 'lit';
import { NDKEvent } from "@nostr-dev-kit/ndk"; import { customElement, state } from 'lit/decorators.js';
@customElement("arx-phora-category-creator") @customElement('arx-phora-category-creator')
export class PhoraCategoryCreator extends LitElement { export class PhoraCategoryCreator extends LitElement {
@state() @state()
private newCategory = ""; private newCategory = '';
@state() @state()
private categoryDescription = ""; private categoryDescription = '';
static override styles = css` static override styles = css`
:host { :host {
@ -33,12 +33,12 @@ export class PhoraCategoryCreator extends LitElement {
private async doCreateCategory() { private async doCreateCategory() {
if (this.newCategory.length < 3) { if (this.newCategory.length < 3) {
alert("Category name must be at least 3 characters long"); alert('Category name must be at least 3 characters long');
return; return;
} }
if (this.categoryDescription.length < 10) { if (this.categoryDescription.length < 10) {
alert("Category description must be at least 10 characters long"); alert('Category description must be at least 10 characters long');
return; return;
} }
@ -46,23 +46,23 @@ export class PhoraCategoryCreator extends LitElement {
await getSigner(); await getSigner();
const event = new NDKEvent(ndk); const event = new NDKEvent(ndk);
event.kind = 11; event.kind = 11;
event.tags = [["subject", this.newCategory]]; event.tags = [['subject', this.newCategory]];
event.content = this.categoryDescription; event.content = this.categoryDescription;
await event.sign(); await event.sign();
await event.publish(); await event.publish();
this.dispatchEvent( this.dispatchEvent(
new CustomEvent("category-created", { new CustomEvent('category-created', {
bubbles: true, bubbles: true,
composed: true, composed: true,
}) }),
); );
this.newCategory = ""; this.newCategory = '';
this.categoryDescription = ""; this.categoryDescription = '';
} catch (error) { } catch (error) {
console.error("Failed to create category:", error); console.error('Failed to create category:', error);
alert("Failed to create category"); alert('Failed to create category');
} }
} }

View file

@ -1,15 +1,15 @@
import { LitElement, html, css } from "lit"; import { getSigner, ndk } from '@/ndk';
import { customElement, property, state } from "lit/decorators.js"; import { NDKEvent } from '@nostr-dev-kit/ndk';
import { getSigner, ndk } from "@/ndk"; import { LitElement, css, html } from 'lit';
import { NDKEvent } from "@nostr-dev-kit/ndk"; import { customElement, property, state } from 'lit/decorators.js';
@customElement("arx-phora-post-creator") @customElement('arx-phora-post-creator')
export class PhoraPostCreator extends LitElement { export class PhoraPostCreator extends LitElement {
@property({ type: String }) @property({ type: String })
topicId = ""; topicId = '';
@state() @state()
private postContent = ""; private postContent = '';
@state() @state()
private isCreating = false; private isCreating = false;
@ -71,7 +71,7 @@ export class PhoraPostCreator extends LitElement {
if (this.isCreating) return; if (this.isCreating) return;
if (this.postContent.length < 10) { if (this.postContent.length < 10) {
this.error = "Post content must be at least 10 characters long"; this.error = 'Post content must be at least 10 characters long';
return; return;
} }
@ -82,27 +82,27 @@ export class PhoraPostCreator extends LitElement {
await getSigner(); await getSigner();
const event = new NDKEvent(ndk); const event = new NDKEvent(ndk);
event.kind = 1111; event.kind = 1111;
event.tags = [["e", this.topicId]]; event.tags = [['e', this.topicId]];
event.content = this.postContent; event.content = this.postContent;
await event.sign(); await event.sign();
await event.publish(); await event.publish();
this.dispatchEvent( this.dispatchEvent(
new CustomEvent("post-created", { new CustomEvent('post-created', {
bubbles: true, bubbles: true,
composed: true, composed: true,
detail: { detail: {
postId: event.id, postId: event.id,
topicId: this.topicId, topicId: this.topicId,
}, },
}) }),
); );
// Reset form // Reset form
this.postContent = ""; this.postContent = '';
} catch (error) { } catch (error) {
console.error("Failed to create post:", error); console.error('Failed to create post:', error);
this.error = "Failed to create post. Please try again."; this.error = 'Failed to create post. Please try again.';
} finally { } finally {
this.isCreating = false; this.isCreating = false;
} }
@ -131,7 +131,7 @@ export class PhoraPostCreator extends LitElement {
<div class="actions"> <div class="actions">
<arx-phora-button <arx-phora-button
@click=${() => this.dispatchEvent(new CustomEvent("cancel"))} @click=${() => this.dispatchEvent(new CustomEvent('cancel'))}
?disabled=${this.isCreating} ?disabled=${this.isCreating}
> >
Cancel Cancel
@ -141,7 +141,7 @@ export class PhoraPostCreator extends LitElement {
@click=${this.doCreatePost} @click=${this.doCreatePost}
?disabled=${this.isCreating} ?disabled=${this.isCreating}
> >
${this.isCreating ? "Creating..." : "Create"} ${this.isCreating ? 'Creating...' : 'Create'}
</arx-phora-button> </arx-phora-button>
</div> </div>
</div> </div>

View file

@ -1,18 +1,18 @@
import { LitElement, html, css } from "lit"; import { getSigner, ndk } from '@/ndk';
import { customElement, property, state } from "lit/decorators.js"; import { NDKEvent } from '@nostr-dev-kit/ndk';
import { getSigner, ndk } from "@/ndk"; import { LitElement, css, html } from 'lit';
import { NDKEvent } from "@nostr-dev-kit/ndk"; import { customElement, property, state } from 'lit/decorators.js';
@customElement("arx-phora-topic-creator") @customElement('arx-phora-topic-creator')
export class PhoraTopicCreator extends LitElement { export class PhoraTopicCreator extends LitElement {
@property({ type: String }) @property({ type: String })
categoryId = ""; categoryId = '';
@state() @state()
private newTopic = ""; private newTopic = '';
@state() @state()
private topicContent = ""; private topicContent = '';
@state() @state()
private isCreating = false; private isCreating = false;
@ -52,12 +52,12 @@ export class PhoraTopicCreator extends LitElement {
if (this.isCreating) return; if (this.isCreating) return;
if (this.newTopic.length < 3) { if (this.newTopic.length < 3) {
alert("Topic title must be at least 3 characters long"); alert('Topic title must be at least 3 characters long');
return; return;
} }
if (this.topicContent.length < 10) { if (this.topicContent.length < 10) {
alert("Topic content must be at least 10 characters long"); alert('Topic content must be at least 10 characters long');
return; return;
} }
@ -68,29 +68,29 @@ export class PhoraTopicCreator extends LitElement {
const event = new NDKEvent(ndk); const event = new NDKEvent(ndk);
event.kind = 11; event.kind = 11;
event.tags = [ event.tags = [
["subject", this.newTopic], ['subject', this.newTopic],
["e", this.categoryId], ['e', this.categoryId],
]; ];
event.content = this.topicContent; event.content = this.topicContent;
await event.sign(); await event.sign();
await event.publish(); await event.publish();
this.dispatchEvent( this.dispatchEvent(
new CustomEvent("topic-created", { new CustomEvent('topic-created', {
bubbles: true, bubbles: true,
composed: true, composed: true,
detail: { detail: {
topicId: event.id, topicId: event.id,
categoryId: this.categoryId, categoryId: this.categoryId,
}, },
}) }),
); );
this.newTopic = ""; this.newTopic = '';
this.topicContent = ""; this.topicContent = '';
} catch (error) { } catch (error) {
console.error("Failed to create topic:", error); console.error('Failed to create topic:', error);
alert("Failed to create topic"); alert('Failed to create topic');
} finally { } finally {
this.isCreating = false; this.isCreating = false;
} }
@ -125,7 +125,7 @@ export class PhoraTopicCreator extends LitElement {
<div class="button-group"> <div class="button-group">
<arx-phora-button <arx-phora-button
@click=${() => this.dispatchEvent(new CustomEvent("cancel"))} @click=${() => this.dispatchEvent(new CustomEvent('cancel'))}
?disabled=${this.isCreating} ?disabled=${this.isCreating}
> >
Cancel Cancel
@ -135,7 +135,7 @@ export class PhoraTopicCreator extends LitElement {
@click=${this.doCreateTopic} @click=${this.doCreateTopic}
?disabled=${this.isCreating} ?disabled=${this.isCreating}
> >
${this.isCreating ? "Creating..." : "Create"} ${this.isCreating ? 'Creating...' : 'Create'}
</arx-phora-button> </arx-phora-button>
</div> </div>
`; `;

View file

@ -1,11 +1,11 @@
import { LitElement, html, css } from "lit"; import { getSigner, ndk } from '@/ndk';
import { customElement, property, state } from "lit/decorators.js"; import type { NDKSubscription } from '@nostr-dev-kit/ndk';
import { getSigner, ndk } from "@/ndk"; import { LitElement, css, html } from 'lit';
import type { NDKSubscription } from "@nostr-dev-kit/ndk"; import { customElement, property, state } from 'lit/decorators.js';
import "@components/Breadcrumbs"; import '@components/Breadcrumbs';
import "@components/ForumPost"; import '@components/ForumPost';
import "@components/PhoraButton"; import '@components/PhoraButton';
interface ForumPost { interface ForumPost {
id: string; id: string;
@ -14,13 +14,13 @@ interface ForumPost {
content: string; content: string;
} }
@customElement("arx-phora-topic-view") @customElement('arx-phora-topic-view')
export class PhoraTopicView extends LitElement { export class PhoraTopicView extends LitElement {
@property({ type: String }) @property({ type: String })
topicId = ""; topicId = '';
@state() @state()
override title = ""; override title = '';
@state() @state()
private posts: ForumPost[] = []; private posts: ForumPost[] = [];
@ -82,10 +82,10 @@ export class PhoraTopicView extends LitElement {
const event = await ndk.fetchEvent(this.topicId); const event = await ndk.fetchEvent(this.topicId);
if (!event) { if (!event) {
throw new Error("Could not load topic"); throw new Error('Could not load topic');
} }
this.title = event.tags.find((tag) => tag[0] === "subject")?.[1] || ""; this.title = event.tags.find((tag) => tag[0] === 'subject')?.[1] || '';
this.posts = [ this.posts = [
{ {
@ -100,9 +100,9 @@ export class PhoraTopicView extends LitElement {
this.subscription = ndk this.subscription = ndk
.subscribe({ .subscribe({
kinds: [1111], kinds: [1111],
"#e": [this.topicId], '#e': [this.topicId],
}) })
.on("event", (event) => { .on('event', (event) => {
this.posts = [ this.posts = [
...this.posts, ...this.posts,
{ {
@ -114,17 +114,13 @@ export class PhoraTopicView extends LitElement {
]; ];
}); });
} catch (error) { } catch (error) {
console.error("Failed to load topic:", error); console.error('Failed to load topic:', error);
alert("Could not load topic"); alert('Could not load topic');
} }
} }
override render() { override render() {
const breadcrumbItems = [ const breadcrumbItems = [{ text: 'Home', href: '/' }, { text: 'Phora', href: '/phora' }, { text: this.title }];
{ text: "Home", href: "/" },
{ text: "Phora", href: "/phora" },
{ text: this.title },
];
return html` return html`
<arx-breadcrumbs .items=${breadcrumbItems}></arx-breadcrumbs> <arx-breadcrumbs .items=${breadcrumbItems}></arx-breadcrumbs>
@ -144,7 +140,7 @@ export class PhoraTopicView extends LitElement {
.date=${post.date} .date=${post.date}
.content=${post.content} .content=${post.content}
></arx-forum-post> ></arx-forum-post>
` `,
)} )}
</div> </div>

View file

@ -1,13 +1,13 @@
import { LitElement, html, css } from "lit"; import type { NDKUserProfile } from '@nostr-dev-kit/ndk';
import { customElement, property, state } from "lit/decorators.js"; import { LitElement, css, html } from 'lit';
import { when } from "lit/directives/when.js"; import { customElement, property, state } from 'lit/decorators.js';
import type { NDKUserProfile } from "@nostr-dev-kit/ndk"; import { when } from 'lit/directives/when.js';
import { getUserProfile } from "../ndk"; import { getUserProfile } from '../ndk';
@customElement("arx-profile-route") @customElement('arx-profile-route')
export class NostrProfile extends LitElement { export class NostrProfile extends LitElement {
@property({ type: String }) @property({ type: String })
npub = ""; npub = '';
@state() @state()
private profile: NDKUserProfile | undefined; private profile: NDKUserProfile | undefined;
@ -282,16 +282,14 @@ export class NostrProfile extends LitElement {
try { try {
this.profile = await getUserProfile(this.npub); this.profile = await getUserProfile(this.npub);
} catch (err) { } catch (err) {
this.error = "Failed to load profile"; this.error = 'Failed to load profile';
console.error(err); console.error(err);
} }
} }
private get displayName() { private get displayName() {
if (!this.profile) return this.npub; if (!this.profile) return this.npub;
return ( return this.profile.displayName || this.profile.name || this.npub.substring(0, 8);
this.profile.displayName || this.profile.name || this.npub.substring(0, 8)
);
} }
override render() { override render() {
@ -313,13 +311,11 @@ export class NostrProfile extends LitElement {
</div> </div>
<div class="banner-overlay"></div> <div class="banner-overlay"></div>
</div> </div>
` `,
)} )}
<div <div
class=${this.profile.banner class=${this.profile.banner ? 'profile-container with-banner' : 'profile-container no-banner'}
? "profile-container with-banner"
: "profile-container no-banner"}
> >
<div class="profile-card"> <div class="profile-card">
<div class="profile-content"> <div class="profile-content">
@ -339,7 +335,7 @@ export class NostrProfile extends LitElement {
class="placeholder-icon" class="placeholder-icon"
></svg-icon> ></svg-icon>
</div> </div>
` `,
)} )}
</div> </div>
@ -354,7 +350,7 @@ export class NostrProfile extends LitElement {
<span class="verified-icon"> <span class="verified-icon">
<svg-icon icon="mdi:check-decagram"></svg-icon> <svg-icon icon="mdi:check-decagram"></svg-icon>
</span> </span>
` `,
)} )}
</h1> </h1>
${when( ${when(
@ -364,15 +360,12 @@ export class NostrProfile extends LitElement {
<svg-icon icon="mdi:at"></svg-icon> <svg-icon icon="mdi:at"></svg-icon>
${this.profile!.nip05} ${this.profile!.nip05}
</p> </p>
` `,
)} )}
</div> </div>
</div> </div>
${when( ${when(this.profile.about, () => html` <p class="bio">${this.profile!.about}</p> `)}
this.profile.about,
() => html` <p class="bio">${this.profile!.about}</p> `
)}
</div> </div>
</div> </div>
@ -388,7 +381,7 @@ export class NostrProfile extends LitElement {
<svg-icon icon="mdi:web" class="link-icon website"></svg-icon> <svg-icon icon="mdi:web" class="link-icon website"></svg-icon>
<span>${this.profile!.website}</span> <span>${this.profile!.website}</span>
</a> </a>
` `,
)} )}
${when( ${when(
this.profile.lud16, this.profile.lud16,
@ -400,7 +393,7 @@ export class NostrProfile extends LitElement {
></svg-icon> ></svg-icon>
<span>${this.profile!.lud16}</span> <span>${this.profile!.lud16}</span>
</a> </a>
` `,
)} )}
</div> </div>
</div> </div>

View file

@ -1,17 +1,17 @@
import "@routes/404Page"; import '@routes/404Page';
import "@routes/Home"; import '@routes/Home';
import "@routes/Profile"; import '@routes/Profile';
import "@routes/Phora/Home"; import '@routes/Phora/Home';
import "@routes/Phora/NewCategory"; import '@routes/Phora/NewCategory';
import "@routes/Phora/NewTopic"; import '@routes/Phora/NewTopic';
import "@routes/Phora/TopicView"; import '@routes/Phora/TopicView';
import "@routes/Phora/NewPost"; import '@routes/Phora/NewPost';
import "@components/InitialSetup"; import '@components/InitialSetup';
import { css, LitElement } from "lit"; import { spread } from '@open-wc/lit-helpers';
import { customElement, property, state } from "lit/decorators.js"; import { LitElement, css } from 'lit';
import { html, literal, type StaticValue } from "lit/static-html.js"; import { customElement, property, state } from 'lit/decorators.js';
import { spread } from "@open-wc/lit-helpers"; import { type StaticValue, html, literal } from 'lit/static-html.js';
export interface RouteParams { export interface RouteParams {
[key: string]: string; [key: string]: string;
@ -26,46 +26,46 @@ interface Route {
meta?: Record<string, string>; meta?: Record<string, string>;
} }
@customElement("arx-eve-router") @customElement('arx-eve-router')
export default class EveRouter extends LitElement { export default class EveRouter extends LitElement {
private static routes: Route[] = [ private static routes: Route[] = [
{ {
pattern: "home", pattern: 'home',
params: {}, params: {},
component: literal`arx-eve-home`, component: literal`arx-eve-home`,
}, },
{ {
pattern: "profile/:npub", pattern: 'profile/:npub',
params: {}, params: {},
component: literal`arx-profile-route`, component: literal`arx-profile-route`,
}, },
{ {
pattern: "phora", pattern: 'phora',
params: {}, params: {},
component: literal`arx-phora-home`, component: literal`arx-phora-home`,
}, },
{ {
pattern: "phora/new-category", pattern: 'phora/new-category',
params: {}, params: {},
component: literal`arx-phora-category-creator`, component: literal`arx-phora-category-creator`,
}, },
{ {
pattern: "phora/new-topic/:categoryId", pattern: 'phora/new-topic/:categoryId',
params: {}, params: {},
component: literal`arx-phora-topic-creator`, component: literal`arx-phora-topic-creator`,
}, },
{ {
pattern: "phora/topics/:topicId", pattern: 'phora/topics/:topicId',
params: {}, params: {},
component: literal`arx-phora-topic-view`, component: literal`arx-phora-topic-view`,
}, },
{ {
pattern: "phora/new-post/:topicId", pattern: 'phora/new-post/:topicId',
params: {}, params: {},
component: literal`arx-phora-post-creator`, component: literal`arx-phora-post-creator`,
}, },
{ {
pattern: "404", pattern: '404',
params: {}, params: {},
component: literal`arx-404-page`, component: literal`arx-404-page`,
}, },
@ -116,8 +116,7 @@ export default class EveRouter extends LitElement {
constructor() { constructor() {
super(); super();
this.initializeRouter(); this.initializeRouter();
if (this.ccnSetup) if (this.ccnSetup) window.relay.start(localStorage.getItem('encryption_key')!);
window.relay.start(localStorage.getItem("encryption_key")!);
} }
override connectedCallback(): void { override connectedCallback(): void {
@ -127,8 +126,8 @@ export default class EveRouter extends LitElement {
override disconnectedCallback(): void { override disconnectedCallback(): void {
super.disconnectedCallback(); super.disconnectedCallback();
window.removeEventListener("hashchange", this.handleHashChange); window.removeEventListener('hashchange', this.handleHashChange);
window.removeEventListener("popstate", this.handlePopState); window.removeEventListener('popstate', this.handlePopState);
} }
private initializeRouter(): void { private initializeRouter(): void {
@ -139,8 +138,8 @@ export default class EveRouter extends LitElement {
} }
private setupEventListeners(): void { private setupEventListeners(): void {
window.addEventListener("hashchange", this.handleHashChange.bind(this)); window.addEventListener('hashchange', this.handleHashChange.bind(this));
window.addEventListener("popstate", this.handlePopState.bind(this)); window.addEventListener('popstate', this.handlePopState.bind(this));
} }
private handleHashChange(): void { private handleHashChange(): void {
@ -161,12 +160,9 @@ export default class EveRouter extends LitElement {
this.currentIndex = this.history.length - 1; this.currentIndex = this.history.length - 1;
} }
private matchRoute( private matchRoute(pattern: string, path: string): { isMatch: boolean; params: RouteParams } {
pattern: string, const patternParts = pattern.split('/').filter(Boolean);
path: string const pathParts = path.split('/').filter(Boolean);
): { isMatch: boolean; params: RouteParams } {
const patternParts = pattern.split("/").filter(Boolean);
const pathParts = path.split("/").filter(Boolean);
const params: RouteParams = {}; const params: RouteParams = {};
if (patternParts.length !== pathParts.length) { if (patternParts.length !== pathParts.length) {
@ -175,7 +171,7 @@ export default class EveRouter extends LitElement {
const isMatch = patternParts.every((patternPart, index) => { const isMatch = patternParts.every((patternPart, index) => {
const pathPart = pathParts[index]; const pathPart = pathParts[index];
if (patternPart.startsWith(":")) { if (patternPart.startsWith(':')) {
const paramName = patternPart.slice(1); const paramName = patternPart.slice(1);
params[paramName] = decodeURIComponent(pathPart); params[paramName] = decodeURIComponent(pathPart);
return true; return true;
@ -188,15 +184,12 @@ export default class EveRouter extends LitElement {
get currentPath(): string { get currentPath(): string {
const hash = window.location.hash?.slice(1); const hash = window.location.hash?.slice(1);
return hash === "" ? "home" : hash; return hash === '' ? 'home' : hash;
} }
get currentRoute(): Route { get currentRoute(): Route {
const route = EveRouter.routes.find((route) => { const route = EveRouter.routes.find((route) => {
const { isMatch, params } = this.matchRoute( const { isMatch, params } = this.matchRoute(route.pattern, this.currentPath);
route.pattern,
this.currentPath
);
if (isMatch) { if (isMatch) {
route.params = params; route.params = params;
return true; return true;
@ -208,7 +201,7 @@ export default class EveRouter extends LitElement {
private getNotFoundRoute(): Route { private getNotFoundRoute(): Route {
return { return {
pattern: "404", pattern: '404',
params: {}, params: {},
component: literal`arx-404-page`, component: literal`arx-404-page`,
}; };

View file

@ -1,4 +1,4 @@
import type { NDKUserProfile } from "@nostr-dev-kit/ndk"; import type { NDKUserProfile } from '@nostr-dev-kit/ndk';
interface ProfileProps { interface ProfileProps {
profile: NDKUserProfile; profile: NDKUserProfile;

View file

@ -14,7 +14,7 @@ function formatSatsGroup(sats: number): string {
.join('') .join('')
.match(/.{1,3}/g) .match(/.{1,3}/g)
?.reverse() ?.reverse()
.map(group => group.split('').reverse().join('')) .map((group) => group.split('').reverse().join(''))
.join(' ') || '0' .join(' ') || '0'
); );
} }
@ -29,10 +29,7 @@ function formatBtcGroup(sats: number): string {
?.join(' ')} BTC`.trim(); ?.join(' ')} BTC`.trim();
} }
export default function satsComma( export default function satsComma(sats: number, format: SatcommaFormat = SatcommaFormat.SATS): string {
sats: number,
format: SatcommaFormat = SatcommaFormat.SATS,
): string {
if (!Number.isFinite(sats)) { if (!Number.isFinite(sats)) {
throw new Error('Invalid input: sats must be a finite number'); throw new Error('Invalid input: sats must be a finite number');
} }
@ -41,7 +38,5 @@ export default function satsComma(
return `-${satsComma(Math.abs(sats), format)}`; return `-${satsComma(Math.abs(sats), format)}`;
} }
return format === SatcommaFormat.SATS return format === SatcommaFormat.SATS ? formatSatsGroup(sats) : formatBtcGroup(sats);
? formatSatsGroup(sats)
: formatBtcGroup(sats);
} }