mirror of
https://github.com/sonr-io/sonr.git
synced 2026-08-02 17:31:39 +00:00
Feat/add networks (#1303)
* No commit suggestions generated * No commit suggestions generated * No commit suggestions generated
This commit is contained in:
@@ -1,173 +0,0 @@
|
||||
---
|
||||
title: Requesting Permissions
|
||||
description: A guide to setting up and managing wallet connections with the Sonr decentralized identity system
|
||||
icon: "shield-check"
|
||||
---
|
||||
|
||||
Sonr provides a seamless and secure way for users to connect their wallets to decentralized applications. This guide covers the different methods for establishing and managing wallet connections, from simple browser-based interactions to backend service integrations.
|
||||
|
||||
## The Sonr Connection Model
|
||||
|
||||
Unlike traditional Web3 wallets that require browser extensions, Sonr uses a combination of WebAuthn and Decentralized Identifiers (DIDs) to create a secure, passwordless connection experience.
|
||||
|
||||
<CardGroup>
|
||||
<Card title="User-Centric" href="/blockchain/modules/did/">
|
||||
Users control their identity and grant permissions to applications, not the
|
||||
other way around.
|
||||
</Card>
|
||||
<Card title="Passwordless" href="/blockchain/modules/did/">
|
||||
WebAuthn enables biometric and security key authentication, eliminating the
|
||||
need for seed phrases.
|
||||
</Card>
|
||||
<Card title="Multi-Device" href="/blockchain/modules/dwn/">
|
||||
Users can securely access their Vault from any device with a modern web
|
||||
browser.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Connecting in the Browser
|
||||
|
||||
For web applications, the Sonr SDK provides a simple way to initiate a wallet connection.
|
||||
|
||||
<Steps>
|
||||
<Step>
|
||||
### 1. Initialize the SDK
|
||||
|
||||
First, initialize the Sonr SDK in your application. For this example, we'll use the CDN version.
|
||||
|
||||
```html
|
||||
<script type="module">
|
||||
import { Sonr } from "https://cdn.jsdelivr.net/npm/@sonr/sdk";
|
||||
const sonr = new Sonr({ httpUrl: "http://localhost:1317" });
|
||||
</script>
|
||||
```
|
||||
|
||||
</Step>
|
||||
|
||||
<Step>
|
||||
### 2. Request Authentication
|
||||
|
||||
Use the `sonr.authenticate()` method to prompt the user to connect their wallet. This will trigger the browser's WebAuthn flow.
|
||||
|
||||
```javascript
|
||||
async function connectWallet() {
|
||||
try {
|
||||
const session = await sonr.authenticate();
|
||||
console.log("Wallet connected!", session);
|
||||
// You now have a secure session with the user's Vault
|
||||
} catch (error) {
|
||||
console.error("Failed to connect wallet:", error);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
</Step>
|
||||
|
||||
<Step>
|
||||
### 3. Handle the Session
|
||||
|
||||
The `session` object returned from `authenticate()` contains the user's DID and a UCAN token with the requested permissions. You can use this session to interact with the user's Vault.
|
||||
|
||||
```javascript
|
||||
// Example: Get the user's balance
|
||||
const balance = await session.vault.getAccountBalance();
|
||||
console.log("User balance:", balance);
|
||||
```
|
||||
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## Backend Wallet Connections
|
||||
|
||||
For backend services, you can use the Sonr SDK to interact with user Vaults on behalf of your application.
|
||||
|
||||
<Steps>
|
||||
<Step>
|
||||
### 1. Service Registration
|
||||
|
||||
Your backend service must be registered on the Sonr network. This provides your service with its own DID and allows it to request permissions from users.
|
||||
|
||||
{/* Service registration documentation is referenced but not yet available in the docs structure */}
|
||||
|
||||
</Step>
|
||||
|
||||
<Step>
|
||||
### 2. Requesting Permissions
|
||||
|
||||
Your service can request permissions from users by generating a UCAN request. This is typically done through a user-facing application.
|
||||
|
||||
```typescript
|
||||
// Example: Requesting permission to read a user's profile
|
||||
const ucanRequest = await sonr.ucan.request({
|
||||
audience: "did:sonr:your-service-did",
|
||||
resource: `dwn://user-did/profile/read`,
|
||||
});
|
||||
|
||||
// Present this request to the user to be signed by their Vault
|
||||
```
|
||||
|
||||
</Step>
|
||||
|
||||
<Step>
|
||||
### 3. Using Delegated Capabilities
|
||||
|
||||
Once a user has approved your request, you will receive a delegated UCAN token. You can use this token to perform actions on the user's behalf.
|
||||
|
||||
```go
|
||||
// Example: Using a delegated UCAN in a Go backend
|
||||
import "github.com/sonr-io/sonr/x/sonr/pkgs/sdk"
|
||||
|
||||
func GetUserProfile(userDID string, delegatedUcan string) (*Profile, error) {
|
||||
sonr, _ := sdk.NewSonr(rpcEndpoint, "")
|
||||
|
||||
// Use the delegated UCAN to access the user's profile
|
||||
profile, err := sonr.GetUserProfile(userDID, delegatedUcan)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return profile, nil
|
||||
}
|
||||
```
|
||||
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## Managing Connections
|
||||
|
||||
### Checking Connection Status
|
||||
|
||||
You can check the current connection status at any time:
|
||||
|
||||
```javascript
|
||||
const session = await sonr.getSession();
|
||||
|
||||
if (session) {
|
||||
console.log("User is connected:", session.did);
|
||||
} else {
|
||||
console.log("User is not connected.");
|
||||
}
|
||||
```
|
||||
|
||||
### Disconnecting
|
||||
|
||||
To disconnect a wallet, simply clear the session from your application's state:
|
||||
|
||||
```javascript
|
||||
await sonr.logout();
|
||||
console.log("User has been disconnected.");
|
||||
```
|
||||
|
||||
This will revoke the current session's UCAN token, but it will not remove any permissions the user has granted to your service.
|
||||
|
||||
## Security Considerations
|
||||
|
||||
- **UCAN Scopes**: Always request the minimum permissions necessary for your application to function.
|
||||
- **Token Storage**: Securely store delegated UCAN tokens on your backend. Never expose them on the client-side.
|
||||
- **Revocation**: Your application should handle UCAN revocations gracefully.
|
||||
|
||||
## Next Steps
|
||||
|
||||
- [Sending Payments](/highway/wallets/sending-payments)
|
||||
- [Understanding UCANs](/blockchain/modules/svc/ucan)
|
||||
- [Explore DWN Architecture](/blockchain/modules/dwn/)
|
||||
@@ -1,233 +0,0 @@
|
||||
---
|
||||
title: "Motor WASM Service Worker Usage"
|
||||
description: "Comprehensive guide to using the Motor WASM service worker for secure browser-based DWN and Wallet APIs"
|
||||
icon: "microchip"
|
||||
sidebarTitle: "Motor WASM"
|
||||
---
|
||||
|
||||
<Info>
|
||||
Motor is a WebAssembly service worker providing secure, client-side cryptographic operations and decentralized web node (DWN) capabilities.
|
||||
</Info>
|
||||
|
||||
## Overview
|
||||
|
||||
Motor is a WebAssembly-powered service worker that enables:
|
||||
- Secure client-side cryptographic operations
|
||||
- Decentralized Web Node (DWN) APIs
|
||||
- Cross-platform support for browsers and Node.js
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="DWN API" icon="database">
|
||||
Create, read, update, and delete records with optional encryption
|
||||
</Card>
|
||||
<Card title="Wallet API" icon="wallet" color="#22863a">
|
||||
UCAN token generation, digital signatures, and verification
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Prerequisites
|
||||
|
||||
<Check>
|
||||
- Node.js 20+ and pnpm
|
||||
- Browser with Service Worker support
|
||||
- HTTP/HTTPS server for WASM files
|
||||
</Check>
|
||||
|
||||
## Installation
|
||||
|
||||
<CodeGroup>
|
||||
```bash npm
|
||||
npm install @sonr.io/es
|
||||
```
|
||||
|
||||
```bash pnpm
|
||||
pnpm add @sonr.io/es
|
||||
```
|
||||
|
||||
```bash yarn
|
||||
yarn add @sonr.io/es
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
## Usage Examples
|
||||
|
||||
### Basic Initialization
|
||||
|
||||
<Tabs>
|
||||
<Tab title="Browser Auto-Detection">
|
||||
```typescript
|
||||
import { createMotorPlugin } from '@sonr.io/es/client/motor';
|
||||
|
||||
// Automatically detects browser vs Node.js environment
|
||||
const plugin = await createMotorPlugin();
|
||||
|
||||
// Get issuer DID
|
||||
const issuer = await plugin.getIssuerDID();
|
||||
console.log('Issuer DID:', issuer.issuer_did);
|
||||
```
|
||||
</Tab>
|
||||
|
||||
<Tab title="Browser Service Worker">
|
||||
```typescript
|
||||
import { createMotorPluginForBrowser } from '@sonr.io/es/client/motor';
|
||||
|
||||
const plugin = await createMotorPluginForBrowser('/motor-worker', {
|
||||
auto_register_worker: true,
|
||||
worker_scope: '/',
|
||||
debug: true,
|
||||
});
|
||||
|
||||
// Create UCAN origin token
|
||||
const tokenResponse = await plugin.newOriginToken({
|
||||
audience_did: 'did:sonr:audience123',
|
||||
attenuations: [{ can: ['sign', 'verify'], with: 'vault://my-vault' }],
|
||||
});
|
||||
```
|
||||
</Tab>
|
||||
|
||||
<Tab title="Node.js">
|
||||
```typescript
|
||||
import { createMotorPluginForNode } from '@sonr.io/es/client/motor';
|
||||
|
||||
const plugin = await createMotorPluginForNode('http://localhost:8080', {
|
||||
max_retries: 3,
|
||||
retry_delay: 1000,
|
||||
timeout: 5000,
|
||||
debug: true,
|
||||
});
|
||||
```
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
### Record Operations
|
||||
|
||||
<CodeGroup>
|
||||
```typescript DWN Create
|
||||
const createResult = await plugin.createRecord({
|
||||
schema: 'https://schema.org/Person',
|
||||
data: JSON.stringify({ name: 'Alice Smith' }),
|
||||
is_encrypted: false,
|
||||
});
|
||||
```
|
||||
|
||||
```typescript DWN Read
|
||||
const record = await plugin.readRecord({
|
||||
record_id: createResult.record_id,
|
||||
});
|
||||
```
|
||||
|
||||
```typescript DWN Update
|
||||
await plugin.updateRecord({
|
||||
record_id: createResult.record_id,
|
||||
data: JSON.stringify({ name: 'Alice Johnson' }),
|
||||
});
|
||||
```
|
||||
|
||||
```typescript DWN Delete
|
||||
const deleteResult = await plugin.deleteRecord({
|
||||
record_id: createResult.record_id,
|
||||
});
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
### Encrypted Records
|
||||
|
||||
```typescript
|
||||
const sensitiveData = {
|
||||
ssn: '123-45-6789',
|
||||
medical_record: 'Confidential information',
|
||||
};
|
||||
|
||||
const encryptedRecord = await plugin.createRecord({
|
||||
schema: 'https://schema.org/MedicalRecord',
|
||||
data: JSON.stringify(sensitiveData),
|
||||
is_encrypted: true, // Enable encryption
|
||||
});
|
||||
|
||||
// Automatic decryption on read
|
||||
const decryptedRecord = await plugin.readRecord({
|
||||
record_id: encryptedRecord.record_id,
|
||||
});
|
||||
```
|
||||
|
||||
## Deployment
|
||||
|
||||
<Tabs>
|
||||
<Tab title="Development">
|
||||
```bash
|
||||
cd dist/wasm
|
||||
python3 -m http.server 8080
|
||||
# Access at http://localhost:8080/test.html
|
||||
```
|
||||
</Tab>
|
||||
|
||||
<Tab title="Production (Nginx)">
|
||||
```nginx
|
||||
location /motor/ {
|
||||
alias /path/to/dist/wasm/;
|
||||
|
||||
# CORS and MIME types
|
||||
add_header 'Access-Control-Allow-Origin' '*';
|
||||
|
||||
location ~ \.wasm$ {
|
||||
add_header 'Content-Type' 'application/wasm';
|
||||
}
|
||||
}
|
||||
```
|
||||
</Tab>
|
||||
|
||||
<Tab title="CDN">
|
||||
```html
|
||||
<script src="https://cdn.example.com/motor/wasm_exec.js"></script>
|
||||
<script>
|
||||
navigator.serviceWorker.register(
|
||||
'https://cdn.example.com/motor/motr-sw.js'
|
||||
);
|
||||
</script>
|
||||
```
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
<Accordion title="Common Issues">
|
||||
<Accordion.Panel title="Service Worker Not Registering">
|
||||
- Ensure HTTPS or localhost
|
||||
- Check browser console
|
||||
- Verify service worker file path
|
||||
</Accordion.Panel>
|
||||
|
||||
<Accordion.Panel title="WASM Module Loading">
|
||||
- Check MIME type: `application/wasm`
|
||||
- Verify CORS headers
|
||||
- Match `wasm_exec.js` with Go version
|
||||
</Accordion.Panel>
|
||||
</Accordion>
|
||||
|
||||
## Browser Compatibility
|
||||
|
||||
| Browser | Minimum Version | Support |
|
||||
|---------|----------------|---------|
|
||||
| Chrome | 89+ | Full |
|
||||
| Firefox | 89+ | Full |
|
||||
| Safari | 15.4+ | Good |
|
||||
| Edge | 89+ | Full |
|
||||
|
||||
<Warning>
|
||||
Requires HTTPS or localhost for service worker functionality
|
||||
</Warning>
|
||||
|
||||
## Performance Tips
|
||||
|
||||
<Tip>
|
||||
- Use TinyGo for smaller WASM binaries
|
||||
- Enable browser caching
|
||||
- Lazy load Motor plugin
|
||||
- Limit service worker scope
|
||||
</Tip>
|
||||
|
||||
## Support
|
||||
|
||||
- **GitHub**: [Issues](https://github.com/sonr-io/sonr/issues)
|
||||
- **Docs**: [Motor WASM Documentation](https://docs.sonr.io/motor-wasm)
|
||||
- **Discord**: [Sonr Community](https://discord.gg/sonr)
|
||||
@@ -1,172 +0,0 @@
|
||||
---
|
||||
title: "PDK Environment Configuration"
|
||||
description: "Comprehensive guide to configuring the Pluggable Development Kit (PDK) for Sonr plugins"
|
||||
icon: "gear"
|
||||
---
|
||||
|
||||
# PDK Environment Configuration
|
||||
|
||||
The Pluggable Development Kit (PDK) provides a flexible configuration system for managing plugin environments, MPC enclaves, and runtime settings.
|
||||
|
||||
## Environment Variables
|
||||
|
||||
### Core PDK Variables
|
||||
|
||||
| Variable | Type | Description | Default |
|
||||
| -------------- | -------- | --------------------------------- | ------------------ |
|
||||
| `chain_id` | `string` | Target blockchain network | `"sonr-testnet-1"` |
|
||||
| `enclave` | `object` | MPC enclave configuration | `{}` |
|
||||
| `vault_config` | `object` | Vault and key management settings | `{}` |
|
||||
| `log_level` | `string` | Logging verbosity | `"info"` |
|
||||
|
||||
## Enclave Configuration
|
||||
|
||||
### Basic Enclave Setup
|
||||
|
||||
```json
|
||||
{
|
||||
"enclave": {
|
||||
"id": "unique-enclave-identifier",
|
||||
"key_type": "secp256k1",
|
||||
"threshold": 2,
|
||||
"participants": [
|
||||
{ "id": "participant1", "public_key": "..." },
|
||||
{ "id": "participant2", "public_key": "..." }
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Advanced Enclave Parameters
|
||||
|
||||
```json
|
||||
{
|
||||
"enclave": {
|
||||
"security_level": "high",
|
||||
"attestation_mode": "remote",
|
||||
"key_rotation_interval": "1h",
|
||||
"backup_strategy": "distributed"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Vault Configuration
|
||||
|
||||
### Key Management Settings
|
||||
|
||||
```json
|
||||
{
|
||||
"vault_config": {
|
||||
"storage_backend": "ipfs",
|
||||
"encryption": {
|
||||
"algorithm": "aes-256-gcm",
|
||||
"key_derivation": "pbkdf2"
|
||||
},
|
||||
"access_control": {
|
||||
"mode": "role-based",
|
||||
"default_role": "viewer"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Logging Configuration
|
||||
|
||||
```json
|
||||
{
|
||||
"log_level": "debug",
|
||||
"log_format": "json",
|
||||
"log_outputs": [
|
||||
{ "type": "stdout" },
|
||||
{ "type": "file", "path": "/var/log/sonr/pdk.log" }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Performance Tuning
|
||||
|
||||
```json
|
||||
{
|
||||
"performance": {
|
||||
"max_concurrent_tasks": 10,
|
||||
"task_timeout": "5m",
|
||||
"memory_limit": "512MB",
|
||||
"cpu_allocation": 2
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Security Hardening
|
||||
|
||||
```json
|
||||
{
|
||||
"security": {
|
||||
"require_mfa": true,
|
||||
"allowed_key_types": ["secp256k1", "ed25519"],
|
||||
"audit_logging": true,
|
||||
"rate_limiting": {
|
||||
"max_requests_per_minute": 100
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Plugin-Specific Configuration
|
||||
|
||||
```json
|
||||
{
|
||||
"plugins": {
|
||||
"motor": {
|
||||
"mpc_mode": "distributed",
|
||||
"token_generation_rate_limit": 10
|
||||
},
|
||||
"did": {
|
||||
"supported_methods": ["did:key", "did:sonr"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Environment Loading Precedence
|
||||
|
||||
1. Environment Variables
|
||||
2. Configuration Files
|
||||
3. Default Values
|
||||
|
||||
## Best Practices
|
||||
|
||||
- Use environment-specific configurations
|
||||
- Implement strict access controls
|
||||
- Rotate encryption keys regularly
|
||||
- Monitor and log configuration changes
|
||||
- Use minimal privilege principles
|
||||
|
||||
## Example Configuration Loading
|
||||
|
||||
```go
|
||||
func loadPDKConfiguration() (*PDKConfig, error) {
|
||||
// Load from environment variables
|
||||
config := &PDKConfig{}
|
||||
|
||||
// Override with config file if exists
|
||||
configFile, err := ioutil.ReadFile("/etc/sonr/pdk.json")
|
||||
if err == nil {
|
||||
json.Unmarshal(configFile, config)
|
||||
}
|
||||
|
||||
return config, nil
|
||||
}
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- Check `log_level` for detailed diagnostics
|
||||
- Validate JSON configuration syntax
|
||||
- Verify key and enclave configurations
|
||||
|
||||
## Advanced Topics
|
||||
|
||||
For more complex PDK configurations, refer to:
|
||||
|
||||
- [DWN Plugin Documentation](/blockchain/modules/dwn/plugin)
|
||||
- [DWN Architecture Overview](/blockchain/modules/dwn/architecture)
|
||||
@@ -1,438 +0,0 @@
|
||||
---
|
||||
title: "Sign in with Sonr: Developer Guide"
|
||||
description: "OAuth 2.0 authentication for decentralized applications with UCAN capabilities"
|
||||
sidebarTitle: "Sign in with Sonr"
|
||||
icon: "key"
|
||||
---
|
||||
|
||||
<Info>
|
||||
This guide covers OAuth 2.0 authentication for decentralized applications using Sonr's advanced Web3 capabilities.
|
||||
</Info>
|
||||
|
||||
## Overview
|
||||
|
||||
Sign in with Sonr provides OAuth 2.0 authentication for decentralized applications, combining traditional OAuth flows with Web3 capabilities through UCAN (User Controlled Authorization Networks) delegation.
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="OAuth 2.0 + OIDC" icon="lock">
|
||||
Industry-standard authentication with OpenID Connect
|
||||
</Card>
|
||||
<Card title="WebAuthn Support" icon="fingerprint">
|
||||
Passwordless authentication with hardware security
|
||||
</Card>
|
||||
<Card title="UCAN Capabilities" icon="network">
|
||||
Fine-grained permission delegation for Web3
|
||||
</Card>
|
||||
<Card title="Decentralized Identity" icon="id-card">
|
||||
W3C DID-based identity management
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Quick Start
|
||||
|
||||
### Installation
|
||||
|
||||
<CodeGroup>
|
||||
```bash npm
|
||||
npm install @sonr.io/ui
|
||||
```
|
||||
```bash pnpm
|
||||
pnpm add @sonr.io/ui
|
||||
```
|
||||
```bash yarn
|
||||
yarn add @sonr.io/ui
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
### Basic Implementation
|
||||
|
||||
<CodeGroup>
|
||||
```tsx React
|
||||
import { SignInWithSonr } from '@sonr.io/ui';
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<SignInWithSonr
|
||||
clientId="your-client-id"
|
||||
redirectUri="http://localhost:3000/callback"
|
||||
scopes={['openid', 'profile', 'vault:read']}
|
||||
/>
|
||||
);
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
## Configuration
|
||||
|
||||
### OAuth Client Registration
|
||||
|
||||
<CodeGroup>
|
||||
```typescript Configuration
|
||||
const clientConfig = {
|
||||
clientId: 'your-client-id',
|
||||
clientSecret: 'your-client-secret', // Only for confidential clients
|
||||
redirectUris: ['http://localhost:3000/callback'],
|
||||
grantTypes: ['authorization_code', 'refresh_token'],
|
||||
responseTypes: ['code'],
|
||||
scopes: ['openid', 'profile', 'vault:read', 'vault:write'],
|
||||
tokenEndpointAuthMethod: 'none', // For public clients
|
||||
};
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
### Environment Variables
|
||||
|
||||
<CodeGroup>
|
||||
```env OAuth Endpoints
|
||||
# OAuth Endpoints
|
||||
NEXT_PUBLIC_SONR_CLIENT_ID=your-client-id
|
||||
NEXT_PUBLIC_REDIRECT_URI=http://localhost:3000/callback
|
||||
NEXT_PUBLIC_AUTH_URL=https://auth.sonr.io/oauth/authorize
|
||||
NEXT_PUBLIC_TOKEN_URL=https://auth.sonr.io/oauth/token
|
||||
NEXT_PUBLIC_USERINFO_URL=https://auth.sonr.io/oauth/userinfo
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
## OAuth Scopes & UCAN Capabilities
|
||||
|
||||
<Tabs>
|
||||
<Tab title="Standard Scopes">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Scope</th>
|
||||
<th>Description</th>
|
||||
<th>UCAN Capabilities</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>`openid`</td>
|
||||
<td>OpenID Connect identity</td>
|
||||
<td>Basic identity claims</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`profile`</td>
|
||||
<td>User profile information</td>
|
||||
<td>Name, picture, metadata</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`email`</td>
|
||||
<td>Email address</td>
|
||||
<td>Email and verification status</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`offline_access`</td>
|
||||
<td>Refresh token issuance</td>
|
||||
<td>Long-lived access</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</Tab>
|
||||
<Tab title="Vault Scopes">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Scope</th>
|
||||
<th>Description</th>
|
||||
<th>UCAN Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>`vault:read`</td>
|
||||
<td>Read vault contents</td>
|
||||
<td>`vault/read`, `vault/list`</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`vault:write`</td>
|
||||
<td>Modify vault contents</td>
|
||||
<td>`vault/write`, `vault/create`, `vault/update`</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`vault:delete`</td>
|
||||
<td>Delete vault items</td>
|
||||
<td>`vault/delete`</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>`vault:admin`</td>
|
||||
<td>Full vault control</td>
|
||||
<td>All vault actions</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
## Integration Examples
|
||||
|
||||
<Tabs>
|
||||
<Tab title="React Hooks">
|
||||
<CodeGroup>
|
||||
```tsx React Hooks
|
||||
import { useSignInWithSonr } from '@sonr.io/ui';
|
||||
|
||||
function LoginComponent() {
|
||||
const {
|
||||
user,
|
||||
token,
|
||||
isAuthenticated,
|
||||
isLoading,
|
||||
signIn,
|
||||
signOut,
|
||||
refreshToken,
|
||||
} = useSignInWithSonr({
|
||||
clientId: 'your-client-id',
|
||||
redirectUri: 'http://localhost:3000/callback',
|
||||
scopes: ['openid', 'profile', 'vault:read'],
|
||||
});
|
||||
|
||||
if (isLoading) return <div>Loading...</div>;
|
||||
|
||||
if (isAuthenticated) {
|
||||
return (
|
||||
<div>
|
||||
<p>Welcome, {user.name}!</p>
|
||||
<button onClick={signOut}>Sign Out</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return <button onClick={signIn}>Sign in with Sonr</button>;
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
</Tab>
|
||||
|
||||
<Tab title="Next.js App Router">
|
||||
<CodeGroup>
|
||||
```tsx Next.js Layout
|
||||
// app/layout.tsx
|
||||
import { AuthProvider } from '@/components/AuthProvider';
|
||||
|
||||
export default function RootLayout({ children }) {
|
||||
return (
|
||||
<html>
|
||||
<body>
|
||||
<AuthProvider>{children}</AuthProvider>
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
```tsx Auth Provider
|
||||
'use client';
|
||||
|
||||
import { createContext, useContext, useEffect, useState } from 'react';
|
||||
import { OAuth2Client } from '@sonr.io/ui';
|
||||
|
||||
const AuthContext = createContext();
|
||||
|
||||
export function AuthProvider({ children }) {
|
||||
const [client] = useState(() => new OAuth2Client({
|
||||
clientId: process.env.NEXT_PUBLIC_SONR_CLIENT_ID,
|
||||
redirectUri: process.env.NEXT_PUBLIC_REDIRECT_URI,
|
||||
}));
|
||||
|
||||
// ... authentication logic
|
||||
|
||||
return (
|
||||
<AuthContext.Provider value={{ client, /* ... */ }}>
|
||||
{children}
|
||||
</AuthContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
export const useAuth = () => useContext(AuthContext);
|
||||
```
|
||||
</CodeGroup>
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
## Advanced Features
|
||||
|
||||
### Custom Authorization
|
||||
|
||||
<CodeGroup>
|
||||
```tsx Custom Authorization
|
||||
<SignInWithSonr
|
||||
clientId="your-client-id"
|
||||
redirectUri="http://localhost:3000/callback"
|
||||
authorizationUrl="https://auth.sonr.io/oauth/authorize"
|
||||
state={generateRandomState()} // CSRF protection
|
||||
scopes={['openid', 'profile', 'vault:admin']}
|
||||
// Additional parameters
|
||||
onAuthStart={() => console.log('Starting auth...')}
|
||||
onAuthError={(error) => console.error('Auth failed:', error)}
|
||||
/>
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
### Token Management
|
||||
|
||||
<CodeGroup>
|
||||
```typescript Token Management
|
||||
const client = new OAuth2Client(config);
|
||||
|
||||
// Check authentication status
|
||||
if (client.isAuthenticated()) {
|
||||
// Get current access token
|
||||
const accessToken = client.getAccessToken();
|
||||
|
||||
// Refresh token before expiry
|
||||
const newToken = await client.refreshToken();
|
||||
|
||||
// Get user information
|
||||
const userInfo = await client.getUserInfo();
|
||||
|
||||
// Revoke tokens on logout
|
||||
await client.logout();
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
## Security Considerations
|
||||
|
||||
<Warning>
|
||||
Always implement robust security practices when integrating authentication.
|
||||
</Warning>
|
||||
|
||||
### PKCE Implementation
|
||||
|
||||
<CodeGroup>
|
||||
```typescript PKCE Configuration
|
||||
const client = new OAuth2Client({
|
||||
clientId: 'public-client',
|
||||
pkce: true, // Enabled by default for public clients
|
||||
});
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
### State Parameter Prevention
|
||||
|
||||
<CodeGroup>
|
||||
```typescript State Validation
|
||||
// Generate random state
|
||||
const state = crypto.randomUUID();
|
||||
sessionStorage.setItem('oauth_state', state);
|
||||
|
||||
// Validate on callback
|
||||
const returnedState = params.get('state');
|
||||
const savedState = sessionStorage.getItem('oauth_state');
|
||||
if (returnedState !== savedState) {
|
||||
throw new Error('State mismatch - possible CSRF attack');
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
<Accordion title="Common Authentication Issues">
|
||||
<AccordionItem title="CORS Errors">
|
||||
- Ensure your redirect URI is whitelisted
|
||||
- Check allowed origins in OAuth server config
|
||||
</AccordionItem>
|
||||
|
||||
<AccordionItem title="Invalid Grant">
|
||||
- Authorization code can only be used once
|
||||
- Code expires after 10 minutes
|
||||
- Verify redirect URI matches exactly
|
||||
</AccordionItem>
|
||||
|
||||
<AccordionItem title="Token Expiry">
|
||||
- Implement automatic refresh before expiry
|
||||
- Handle refresh token rotation
|
||||
</AccordionItem>
|
||||
</Accordion>
|
||||
|
||||
<Note>
|
||||
Enable debug mode for additional troubleshooting insights:
|
||||
```typescript
|
||||
const client = new OAuth2Client({
|
||||
clientId: 'your-client-id',
|
||||
debug: true, // Enable console logging
|
||||
});
|
||||
```
|
||||
</Note>
|
||||
|
||||
## API Reference
|
||||
|
||||
### SignInWithSonr Props
|
||||
|
||||
```typescript
|
||||
interface SignInWithSonrProps {
|
||||
clientId: string;
|
||||
redirectUri: string;
|
||||
authorizationUrl?: string;
|
||||
scopes?: string[];
|
||||
state?: string;
|
||||
variant?: 'default' | 'outline' | 'ghost' | 'dark';
|
||||
size?: 'default' | 'sm' | 'lg';
|
||||
isLoading?: boolean;
|
||||
text?: string;
|
||||
showLogo?: boolean;
|
||||
onAuthStart?: () => void;
|
||||
onAuthError?: (error: Error) => void;
|
||||
}
|
||||
```
|
||||
|
||||
## Resources
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card
|
||||
title="OAuth 2.0 Specification"
|
||||
href="https://datatracker.ietf.org/doc/html/rfc6749"
|
||||
>
|
||||
RFC 6749 - OAuth 2.0 Authorization Framework
|
||||
</Card>
|
||||
|
||||
<Card
|
||||
title="OpenID Connect"
|
||||
href="https://openid.net/specs/openid-connect-core-1_0.html"
|
||||
>
|
||||
Core specification for identity layers
|
||||
</Card>
|
||||
|
||||
<Card
|
||||
title="UCAN Specification"
|
||||
href="https://github.com/ucan-wg/spec"
|
||||
>
|
||||
User Controlled Authorization Networks
|
||||
</Card>
|
||||
|
||||
<Card
|
||||
title="WebAuthn"
|
||||
href="https://www.w3.org/TR/webauthn/"
|
||||
>
|
||||
Web Authentication API specification
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Support
|
||||
|
||||
<CardGroup cols={3}>
|
||||
<Card
|
||||
title="GitHub"
|
||||
icon="github"
|
||||
href="https://github.com/sonr-io/sonr"
|
||||
>
|
||||
Report issues or contribute
|
||||
</Card>
|
||||
|
||||
<Card
|
||||
title="Documentation"
|
||||
icon="book"
|
||||
href="https://sonr.dev"
|
||||
>
|
||||
Explore full documentation
|
||||
</Card>
|
||||
|
||||
<Card
|
||||
title="Discord"
|
||||
icon="discord"
|
||||
href="https://discord.gg/sonr"
|
||||
>
|
||||
Join our community
|
||||
</Card>
|
||||
</CardGroup>
|
||||
@@ -1,286 +0,0 @@
|
||||
---
|
||||
title: "Sonr Vault Plugin with Dexie.js Persistence"
|
||||
description: "Comprehensive guide to using the Sonr Vault Plugin with persistent storage and multi-account support"
|
||||
sidebarTitle: "Vault Plugin Usage"
|
||||
icon: "lock"
|
||||
---
|
||||
|
||||
# Sonr Vault Plugin: Persistent Storage and Account Management
|
||||
|
||||
## Overview
|
||||
|
||||
The Sonr Vault Plugin provides a powerful, secure, and flexible way to manage cryptographic operations with persistent storage using Dexie.js and IndexedDB. This guide will walk you through the plugin's features, setup, and advanced usage patterns.
|
||||
|
||||
<Callout type="info">
|
||||
**Key Features**
|
||||
- 🔐 Account-based database separation
|
||||
- 💾 Automatic token persistence
|
||||
- 🔄 Cross-browser IndexedDB support
|
||||
- ⚡ Backward compatibility
|
||||
- 🧹 Automatic token and session cleanup
|
||||
</Callout>
|
||||
|
||||
## Installation
|
||||
|
||||
Install the Sonr Vault Plugin in your project:
|
||||
|
||||
<CodeGroup>
|
||||
```bash npm
|
||||
npm install @sonr.io/es
|
||||
```
|
||||
|
||||
```bash yarn
|
||||
yarn add @sonr.io/es
|
||||
```
|
||||
|
||||
```bash pnpm
|
||||
pnpm add @sonr.io/es
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
## Basic Usage
|
||||
|
||||
### Without Persistence (Default)
|
||||
|
||||
The vault plugin is designed to be backward compatible. By default, it operates without persistent storage:
|
||||
|
||||
```typescript
|
||||
import { createVaultClient } from '@sonr.io/es/plugins/vault';
|
||||
|
||||
// Create a vault client without persistence
|
||||
const vault = createVaultClient();
|
||||
|
||||
// Initialize the vault
|
||||
await vault.initialize();
|
||||
|
||||
// Create tokens and perform operations as before
|
||||
const token = await vault.newOriginToken({
|
||||
audience_did: 'did:example:123',
|
||||
});
|
||||
```
|
||||
|
||||
### With Persistence Enabled
|
||||
|
||||
Enable persistent storage with a simple configuration:
|
||||
|
||||
```typescript
|
||||
import { createVaultClient } from '@sonr.io/es/plugins/vault';
|
||||
|
||||
// Create a vault client with persistence
|
||||
const vault = createVaultClient({
|
||||
enablePersistence: true,
|
||||
autoCleanup: true, // Automatically clean up expired tokens
|
||||
cleanupInterval: 3600000 // Cleanup every hour (in milliseconds)
|
||||
});
|
||||
|
||||
// Initialize with an account address for database separation
|
||||
const accountAddress = 'sonr1abc123...';
|
||||
await vault.initialize('/plugin.wasm', accountAddress);
|
||||
|
||||
// Tokens are now automatically persisted
|
||||
const token = await vault.newOriginToken({
|
||||
audience_did: 'did:example:123',
|
||||
});
|
||||
```
|
||||
|
||||
## Advanced Features
|
||||
|
||||
### Multi-Account Support
|
||||
|
||||
Seamlessly switch between accounts and manage their individual databases:
|
||||
|
||||
```typescript
|
||||
// Switch to a different account
|
||||
await vault.switchAccount('sonr1account2');
|
||||
|
||||
// List all accounts with persisted data
|
||||
const accounts = await vault.listPersistedAccounts();
|
||||
|
||||
// Remove an account's data
|
||||
await vault.removeAccount('sonr1account1');
|
||||
```
|
||||
|
||||
### Token Management
|
||||
|
||||
Manually manage persisted tokens:
|
||||
|
||||
```typescript
|
||||
// Get all saved tokens
|
||||
const tokens = await vault.getPersistedTokens();
|
||||
|
||||
// Save a specific token
|
||||
await vault.saveToken({
|
||||
token: 'eyJ...',
|
||||
issuer: 'did:sonr:example',
|
||||
address: 'sonr1abc...',
|
||||
});
|
||||
|
||||
// Remove expired tokens
|
||||
await vault.removeExpiredTokens();
|
||||
```
|
||||
|
||||
### State Management
|
||||
|
||||
Control vault state persistence:
|
||||
|
||||
```typescript
|
||||
// Manually save current state
|
||||
await vault.persistState();
|
||||
|
||||
// Load persisted state
|
||||
const state = await vault.loadPersistedState();
|
||||
|
||||
// Clear all persisted data for the current account
|
||||
await vault.clearPersistedState();
|
||||
```
|
||||
|
||||
## Storage Management
|
||||
|
||||
Use the `VaultStorageManager` for advanced storage operations:
|
||||
|
||||
```typescript
|
||||
import { VaultStorageManager } from '@sonr.io/es/plugins/vault';
|
||||
|
||||
const storageManager = new VaultStorageManager({
|
||||
enablePersistence: true,
|
||||
});
|
||||
|
||||
// Request persistent storage
|
||||
const isPersisted = await storageManager.requestPersistentStorage();
|
||||
|
||||
// Check storage status and estimate
|
||||
const status = await storageManager.tryPersistWithoutPromptingUser();
|
||||
const estimate = await storageManager.getStorageEstimate();
|
||||
```
|
||||
|
||||
## Configuration Options
|
||||
|
||||
Customize the vault's storage behavior:
|
||||
|
||||
<TypeTable
|
||||
columns={[
|
||||
{ name: 'enablePersistence', type: 'boolean', description: 'Enable IndexedDB storage' },
|
||||
{ name: 'storageQuotaRequest', type: 'number', description: 'Storage quota to request in bytes' },
|
||||
{ name: 'autoCleanup', type: 'boolean', description: 'Enable automatic token/session cleanup' },
|
||||
{ name: 'cleanupInterval', type: 'number', description: 'Cleanup interval in milliseconds' }
|
||||
]}
|
||||
/>
|
||||
|
||||
## Browser Compatibility
|
||||
|
||||
The Vault Plugin works with most modern browsers:
|
||||
|
||||
<Table>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell>Browser</TableCell>
|
||||
<TableCell>Minimum Version</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell>Chrome/Edge</TableCell>
|
||||
<TableCell>23+</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell>Firefox</TableCell>
|
||||
<TableCell>16+</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell>Safari</TableCell>
|
||||
<TableCell>10+</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell>Opera</TableCell>
|
||||
<TableCell>15+</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell>iOS Safari</TableCell>
|
||||
<TableCell>10+</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell>Chrome for Android</TableCell>
|
||||
<TableCell>All versions</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
</Table>
|
||||
|
||||
## Storage Limits
|
||||
|
||||
Storage availability varies by browser:
|
||||
|
||||
<Table>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell>Browser</TableCell>
|
||||
<TableCell>Storage Limit</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell>Chrome/Edge</TableCell>
|
||||
<TableCell>60% of total disk space</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell>Firefox</TableCell>
|
||||
<TableCell>50% of free disk space</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell>Safari</TableCell>
|
||||
<TableCell>Starts at 1GB, can request more</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell>Mobile Browsers</TableCell>
|
||||
<TableCell>Varies by device</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
</Table>
|
||||
|
||||
## Security Considerations
|
||||
|
||||
<Callout type="warning">
|
||||
- Databases are isolated by account address
|
||||
- No private keys or sensitive cryptographic material are stored
|
||||
- Only UCAN tokens and metadata are persisted
|
||||
- Always use HTTPS in production
|
||||
- Consider encrypting sensitive data before storage
|
||||
</Callout>
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Storage Not Persisting
|
||||
|
||||
1. Verify you're running on HTTPS
|
||||
2. Check that IndexedDB is enabled in browser settings
|
||||
3. Confirm available storage quota
|
||||
4. Explicitly request persistent storage
|
||||
|
||||
```typescript
|
||||
try {
|
||||
await vault.initialize('/plugin.wasm', accountAddress);
|
||||
} catch (error) {
|
||||
if (error.code === 'VAULT_NOT_INITIALIZED') {
|
||||
// Handle initialization error
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Migration Guide
|
||||
|
||||
To migrate from non-persistent to persistent storage:
|
||||
|
||||
```typescript
|
||||
// Before (non-persistent)
|
||||
const vault = createVaultClient();
|
||||
await vault.initialize();
|
||||
|
||||
// After (with persistence)
|
||||
const vault = createVaultClient({
|
||||
enablePersistence: true,
|
||||
});
|
||||
await vault.initialize('/plugin.wasm', accountAddress);
|
||||
```
|
||||
|
||||
<Callout type="success">
|
||||
**No other code changes are required!** All existing methods work the same way.
|
||||
</Callout>
|
||||
@@ -1,191 +0,0 @@
|
||||
---
|
||||
title: Getting Started with Browser/ESM
|
||||
description: A quick start guide for using Sonr in web browsers with WebAuthn integration
|
||||
sidebarTitle: Browser Quickstart
|
||||
icon: "globe"
|
||||
---
|
||||
|
||||
This guide will walk you through creating a simple web application that interacts with the Sonr network directly from the browser. We will use the Sonr JavaScript SDK to create a new user identity, claim a Vault, and send a transaction.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- A local Sonr network running. See the [Validator Setup Guide](/quickstart/validators) for instructions
|
||||
- A modern web browser with WebAuthn support (Chrome, Firefox, Safari, Edge)
|
||||
|
||||
## 1. Project Setup
|
||||
|
||||
<Steps>
|
||||
<Step>
|
||||
### Create an HTML File
|
||||
|
||||
Create a new `index.html` file and add the following basic structure:
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Sonr Browser Quickstart</title>
|
||||
<script type="module" src="app.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Sonr Browser Quickstart</h1>
|
||||
<button id="create-identity">Create Identity</button>
|
||||
<div id="output"></div>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</Step>
|
||||
|
||||
<Step>
|
||||
### Create a JavaScript File
|
||||
|
||||
Create a new `app.js` file in the same directory. This is where we will write our application logic.
|
||||
|
||||
</Step>
|
||||
|
||||
<Step>
|
||||
### Install the Sonr SDK
|
||||
|
||||
For this quickstart, we will use the Sonr SDK from a CDN. Add the following script tag to the `<head>` of your `index.html` file:
|
||||
|
||||
```html
|
||||
<script type="module">
|
||||
import { Sonr, WebAuthn } from "https://cdn.jsdelivr.net/npm/@sonr/sdk";
|
||||
window.Sonr = Sonr;
|
||||
window.WebAuthn = WebAuthn;
|
||||
</script>
|
||||
```
|
||||
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## 2. Creating an Identity
|
||||
|
||||
Now, let's add the logic to create a new user identity and claim a Vault.
|
||||
|
||||
<Steps>
|
||||
<Step>
|
||||
### Add Event Listener
|
||||
|
||||
In `app.js`, add an event listener to the "Create Identity" button:
|
||||
|
||||
```javascript
|
||||
document
|
||||
.getElementById("create-identity")
|
||||
.addEventListener("click", async () => {
|
||||
const output = document.getElementById("output");
|
||||
output.innerHTML = "Creating identity...";
|
||||
|
||||
try {
|
||||
// Code to create identity will go here
|
||||
} catch (error) {
|
||||
output.innerHTML = `Error: ${error.message}`;
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
</Step>
|
||||
|
||||
<Step>
|
||||
### Implement Identity Creation
|
||||
|
||||
Inside the event listener, use the `WebAuthn.createCredential` method to create a new WebAuthn credential and the `Sonr.claimVault` method to claim a new Vault on the network.
|
||||
|
||||
```javascript
|
||||
// Inside the try block
|
||||
const credential = await WebAuthn.createCredential({
|
||||
rp: { name: "Sonr Quickstart" },
|
||||
user: {
|
||||
id: new Uint8Array(16), // Should be a unique user ID
|
||||
name: "user@example.com",
|
||||
displayName: "Test User",
|
||||
},
|
||||
});
|
||||
|
||||
output.innerHTML = `Credential created: ${credential.id}`;
|
||||
|
||||
const sonr = new Sonr({ httpUrl: "http://localhost:1317" });
|
||||
const vault = await sonr.claimVault(credential);
|
||||
|
||||
output.innerHTML = `Vault claimed! DID: ${vault.did}`;
|
||||
```
|
||||
|
||||
<Note type="warning">
|
||||
In a real application, the user ID should be a unique and stable identifier
|
||||
for the user, not a random value.
|
||||
</Note>
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## 3. Running the Application
|
||||
|
||||
To run the application, you need a simple web server. You can use the `http-server` package for this.
|
||||
|
||||
```bash
|
||||
# Install http-server
|
||||
npm install -g http-server
|
||||
|
||||
# Start the server
|
||||
http-server
|
||||
```
|
||||
|
||||
Now, open your browser and navigate to `http://localhost:8080`. When you click the "Create Identity" button, your browser will prompt you to create a new passkey using your device's biometrics or a security key.
|
||||
|
||||
## 4. Sending a Transaction
|
||||
|
||||
Once you have a Vault, you can use it to send transactions.
|
||||
|
||||
<Steps>
|
||||
<Step>
|
||||
### Add a Send Button
|
||||
|
||||
Add a new button to your `index.html` file:
|
||||
|
||||
```html
|
||||
<button id="send-transaction" disabled>Send Transaction</button>
|
||||
```
|
||||
|
||||
</Step>
|
||||
|
||||
<Step>
|
||||
### Implement Transaction Sending
|
||||
|
||||
In `app.js`, add an event listener to the new button. This will use the `sonr.send` method to send a transaction.
|
||||
|
||||
```javascript
|
||||
let vaultInstance;
|
||||
|
||||
// After claiming the vault...
|
||||
vaultInstance = vault;
|
||||
document.getElementById("send-transaction").disabled = false;
|
||||
|
||||
document
|
||||
.getElementById("send-transaction")
|
||||
.addEventListener("click", async () => {
|
||||
const output = document.getElementById("output");
|
||||
output.innerHTML = "Sending transaction...";
|
||||
|
||||
try {
|
||||
const result = await vaultInstance.send({
|
||||
to: "snr1..._recipient_address_...",
|
||||
amount: "1000000usnr", // 1 SNR
|
||||
});
|
||||
|
||||
output.innerHTML = `Transaction successful! TxHash: ${result.txhash}`;
|
||||
} catch (error) {
|
||||
output.innerHTML = `Error: ${error.message}`;
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## Next Steps
|
||||
|
||||
Congratulations! You have successfully created a web application that interacts with the Sonr network. From here, you can explore more advanced features:
|
||||
|
||||
- **Service Registration**: Register your application as a trusted service on the network
|
||||
- **UCAN Authorization**: Request and manage user permissions for your application
|
||||
- **Cross-Chain Operations**: Interact with other blockchains through IBC
|
||||
@@ -1,521 +0,0 @@
|
||||
---
|
||||
title: Getting Started with Golang
|
||||
description: A quick start guide for building applications with Sonr using the Go Client SDK
|
||||
sidebarTitle: Golang Quickstart
|
||||
icon: "golang"
|
||||
---
|
||||
|
||||
This guide provides a walkthrough for setting up a Go project to interact with the Sonr network using the official Go Client SDK. You will learn how to configure the client, manage keys, query the blockchain, send transactions, and use advanced features like WebAuthn gasless transactions.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- A local Sonr network running. See the [Validator Setup Guide](/quickstart/validators) for instructions
|
||||
- Go version 1.24 or higher
|
||||
|
||||
## 1. Project Setup
|
||||
|
||||
<Steps>
|
||||
<Step>
|
||||
### Initialize a Go Module
|
||||
|
||||
Create a new directory for your project and initialize a Go module:
|
||||
|
||||
```bash
|
||||
mkdir sonr-go-quickstart
|
||||
cd sonr-go-quickstart
|
||||
go mod init github.com/your-username/sonr-go-quickstart
|
||||
```
|
||||
|
||||
</Step>
|
||||
|
||||
<Step>
|
||||
### Add the Sonr Client SDK Dependency
|
||||
|
||||
Add the Sonr Client SDK to your project's dependencies:
|
||||
|
||||
```bash
|
||||
go get github.com/sonr-io/sonr/client
|
||||
```
|
||||
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## 2. Client Configuration and Setup
|
||||
|
||||
Let's set up the Sonr client with proper configuration and key management.
|
||||
|
||||
<Steps>
|
||||
<Step>
|
||||
### Create the Main File
|
||||
|
||||
Create a new file named `main.go`.
|
||||
|
||||
</Step>
|
||||
|
||||
<Step>
|
||||
### Initialize the Client
|
||||
|
||||
Add the following code to `main.go` to initialize the Sonr client:
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
|
||||
"github.com/sonr-io/sonr/client/config"
|
||||
"github.com/sonr-io/sonr/client/keys"
|
||||
"github.com/sonr-io/sonr/client/sonr"
|
||||
"github.com/sonr-io/sonr/client/tx"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Use local network configuration
|
||||
cfg := config.LocalNetwork()
|
||||
|
||||
// Establish gRPC connection
|
||||
conn, err := grpc.Dial(
|
||||
cfg.GRPC,
|
||||
grpc.WithTransportCredentials(insecure.NewCredentials()),
|
||||
)
|
||||
if err != nil {
|
||||
log.Fatal("Failed to connect:", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
// Create the Sonr client
|
||||
client, err := sonr.NewClient(&cfg, conn)
|
||||
if err != nil {
|
||||
log.Fatal("Failed to create client:", err)
|
||||
}
|
||||
|
||||
fmt.Println("Sonr client initialized successfully!")
|
||||
fmt.Printf("Connected to: %s\n", cfg.ChainID)
|
||||
}
|
||||
```
|
||||
|
||||
</Step>
|
||||
|
||||
<Step>
|
||||
### Create a Keyring Manager
|
||||
|
||||
Add key management to handle wallet operations:
|
||||
|
||||
```go
|
||||
// Initialize keyring manager (using test backend for development)
|
||||
keyringManager, err := keys.NewKeyringManager(
|
||||
"test", // backend: test, file, os
|
||||
".sonr-keys", // directory for keys
|
||||
cfg.ChainID, // chain ID
|
||||
)
|
||||
if err != nil {
|
||||
log.Fatal("Failed to create keyring:", err)
|
||||
}
|
||||
|
||||
// Create a new wallet
|
||||
walletIdentity, mnemonic, err := keyringManager.CreateWallet(
|
||||
context.Background(),
|
||||
"my-wallet", // wallet name
|
||||
"", // passphrase (empty for test backend)
|
||||
)
|
||||
if err != nil {
|
||||
log.Fatal("Failed to create wallet:", err)
|
||||
}
|
||||
|
||||
fmt.Printf("Wallet created!\n")
|
||||
fmt.Printf("Address: %s\n", walletIdentity.Address)
|
||||
fmt.Printf("DID: %s\n", walletIdentity.DID)
|
||||
fmt.Printf("Mnemonic: %s\n", mnemonic)
|
||||
```
|
||||
|
||||
<Note type="warning">
|
||||
**Important**: In production, use secure keyring backends like "os" or "file" with proper passphrase protection. Never expose mnemonics in your code.
|
||||
</Note>
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## 3. Querying the Blockchain
|
||||
|
||||
Now, let's query the blockchain using the unified query client.
|
||||
|
||||
<Steps>
|
||||
<Step>
|
||||
### Create a Query Client
|
||||
|
||||
Add the query client to your application:
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/sonr-io/sonr/client/query"
|
||||
)
|
||||
|
||||
// Create query client
|
||||
queryClient, err := query.NewQueryClient(conn, &cfg)
|
||||
if err != nil {
|
||||
log.Fatal("Failed to create query client:", err)
|
||||
}
|
||||
```
|
||||
|
||||
</Step>
|
||||
|
||||
<Step>
|
||||
### Query Account Balance
|
||||
|
||||
Query an account's balance:
|
||||
|
||||
```go
|
||||
// Query account balance
|
||||
address := walletIdentity.Address // or any other address
|
||||
balance, err := queryClient.Balance(
|
||||
context.Background(),
|
||||
address,
|
||||
cfg.StakingDenom, // "usnr"
|
||||
)
|
||||
if err != nil {
|
||||
log.Printf("Failed to query balance: %v", err)
|
||||
} else {
|
||||
fmt.Printf("Balance for %s: %s %s\n",
|
||||
address,
|
||||
balance.Balance.Amount.String(),
|
||||
balance.Balance.Denom,
|
||||
)
|
||||
}
|
||||
|
||||
// Query all balances for an account
|
||||
allBalances, err := queryClient.AllBalances(
|
||||
context.Background(),
|
||||
address,
|
||||
nil, // pagination
|
||||
)
|
||||
if err != nil {
|
||||
log.Printf("Failed to query all balances: %v", err)
|
||||
} else {
|
||||
fmt.Printf("All balances: %v\n", allBalances.Balances)
|
||||
}
|
||||
```
|
||||
|
||||
</Step>
|
||||
|
||||
<Step>
|
||||
### Query Module-Specific Data
|
||||
|
||||
Query DID documents and other module data:
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/sonr-io/sonr/client/modules/did"
|
||||
)
|
||||
|
||||
// Create DID module client
|
||||
didClient := did.NewDIDClient()
|
||||
|
||||
// Query DID document (if exists)
|
||||
didID := "did:sonr:example123"
|
||||
didDoc, err := queryClient.GetDID(context.Background(), didID)
|
||||
if err != nil {
|
||||
log.Printf("DID not found: %v", err)
|
||||
} else {
|
||||
fmt.Printf("DID Document: %+v\n", didDoc)
|
||||
}
|
||||
|
||||
// List all DIDs with pagination
|
||||
didList, err := queryClient.ListDIDs(
|
||||
context.Background(),
|
||||
&query.ListOptions{
|
||||
Limit: 10,
|
||||
Offset: 0,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
log.Printf("Failed to list DIDs: %v", err)
|
||||
} else {
|
||||
fmt.Printf("Found %d DIDs\n", len(didList.DIDs))
|
||||
}
|
||||
```
|
||||
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## 4. Building and Broadcasting Transactions
|
||||
|
||||
Let's build and broadcast transactions using the transaction builder.
|
||||
|
||||
<Steps>
|
||||
<Step>
|
||||
### Create a Transaction Builder
|
||||
|
||||
Initialize the transaction builder with gas estimation:
|
||||
|
||||
```go
|
||||
// Create transaction builder
|
||||
txBuilder, err := tx.NewTxBuilder(&cfg, conn)
|
||||
if err != nil {
|
||||
log.Fatal("Failed to create tx builder:", err)
|
||||
}
|
||||
|
||||
// Create broadcaster
|
||||
broadcaster, err := tx.NewBroadcaster(&cfg, conn)
|
||||
if err != nil {
|
||||
log.Fatal("Failed to create broadcaster:", err)
|
||||
}
|
||||
|
||||
// Create gas estimator
|
||||
gasEstimator := tx.NewGasEstimator(conn, &cfg)
|
||||
```
|
||||
|
||||
</Step>
|
||||
|
||||
<Step>
|
||||
### Send Tokens Between Accounts
|
||||
|
||||
Build and broadcast a bank send transaction:
|
||||
|
||||
```go
|
||||
import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
|
||||
)
|
||||
|
||||
// Create a second wallet to receive funds
|
||||
receiver, _, err := keyringManager.CreateWallet(
|
||||
context.Background(),
|
||||
"receiver-wallet",
|
||||
"",
|
||||
)
|
||||
if err != nil {
|
||||
log.Fatal("Failed to create receiver wallet:", err)
|
||||
}
|
||||
|
||||
// Create send message
|
||||
amount := sdk.NewCoins(sdk.NewInt64Coin("usnr", 1000000)) // 1 SNR
|
||||
sendMsg := &banktypes.MsgSend{
|
||||
FromAddress: walletIdentity.Address,
|
||||
ToAddress: receiver.Address,
|
||||
Amount: amount,
|
||||
}
|
||||
|
||||
// Build transaction
|
||||
txBuilder = txBuilder.
|
||||
AddMessage(sendMsg).
|
||||
WithMemo("Test transaction").
|
||||
WithGasLimit(200000)
|
||||
|
||||
// Estimate gas
|
||||
gasEstimate, err := gasEstimator.EstimateGas(
|
||||
context.Background(),
|
||||
[]sdk.Msg{sendMsg},
|
||||
)
|
||||
if err != nil {
|
||||
log.Printf("Gas estimation failed: %v", err)
|
||||
} else {
|
||||
fmt.Printf("Estimated gas: %d\n", gasEstimate.GasLimit)
|
||||
txBuilder = txBuilder.WithGasLimit(gasEstimate.GasLimit)
|
||||
}
|
||||
|
||||
// Calculate and set fee
|
||||
fee := gasEstimator.CalculateFee(
|
||||
gasEstimate.GasLimit,
|
||||
cfg.GasPrice,
|
||||
cfg.StakingDenom,
|
||||
)
|
||||
txBuilder = txBuilder.WithFee(fee)
|
||||
|
||||
// Sign the transaction
|
||||
signedTx, err := txBuilder.Sign(context.Background(), keyringManager)
|
||||
if err != nil {
|
||||
log.Fatal("Failed to sign transaction:", err)
|
||||
}
|
||||
|
||||
// Broadcast the transaction
|
||||
result, err := broadcaster.BroadcastTx(context.Background(), signedTx)
|
||||
if err != nil {
|
||||
log.Fatal("Failed to broadcast transaction:", err)
|
||||
}
|
||||
|
||||
fmt.Printf("Transaction successful!\n")
|
||||
fmt.Printf("TxHash: %s\n", result.TxHash)
|
||||
fmt.Printf("Height: %d\n", result.Height)
|
||||
fmt.Printf("Gas Used: %d\n", result.GasUsed)
|
||||
```
|
||||
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## 5. WebAuthn Gasless Transactions (Advanced)
|
||||
|
||||
Sonr supports gasless WebAuthn registration, allowing users to onboard without holding tokens.
|
||||
|
||||
<Steps>
|
||||
<Step>
|
||||
### Initialize WebAuthn Client
|
||||
|
||||
Set up the WebAuthn client for gasless operations:
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/sonr-io/sonr/client/auth"
|
||||
)
|
||||
|
||||
// Create WebAuthn client
|
||||
webauthnClient := auth.NewWebAuthnClient(
|
||||
keyringManager,
|
||||
"localhost", // Relying Party ID
|
||||
"Sonr Local", // Relying Party Name
|
||||
)
|
||||
|
||||
// Create gasless transaction manager
|
||||
gaslessManager := auth.NewGaslessTransactionManager(
|
||||
txBuilder,
|
||||
broadcaster,
|
||||
&cfg,
|
||||
)
|
||||
|
||||
// Create WebAuthn gasless client
|
||||
gaslessClient := auth.NewWebAuthnGaslessClient(
|
||||
webauthnClient,
|
||||
gaslessManager,
|
||||
&cfg,
|
||||
)
|
||||
```
|
||||
|
||||
</Step>
|
||||
|
||||
<Step>
|
||||
### Initiate Gasless Registration
|
||||
|
||||
Start a gasless WebAuthn registration:
|
||||
|
||||
```go
|
||||
// Begin gasless registration
|
||||
registrationResult, err := gaslessClient.RegisterGasless(
|
||||
context.Background(),
|
||||
"alice", // username
|
||||
"Alice Smith", // display name
|
||||
)
|
||||
if err != nil {
|
||||
log.Fatal("Failed to initiate registration:", err)
|
||||
}
|
||||
|
||||
fmt.Printf("Registration initiated!\n")
|
||||
fmt.Printf("Gasless eligible: %v\n", registrationResult.GaslessEligible)
|
||||
fmt.Printf("Estimated gas: %d\n", registrationResult.EstimatedGas)
|
||||
|
||||
// The challenge would be sent to a browser for completion
|
||||
// In a real application, you'd handle the browser response
|
||||
```
|
||||
|
||||
</Step>
|
||||
|
||||
<Step>
|
||||
### Check Gasless Eligibility
|
||||
|
||||
Verify if a transaction is eligible for gasless processing:
|
||||
|
||||
```go
|
||||
// Check if messages are eligible for gasless
|
||||
msgs := []sdk.Msg{
|
||||
&didtypes.MsgRegisterWebAuthnCredential{
|
||||
Controller: "sonr1...",
|
||||
Username: "alice",
|
||||
},
|
||||
}
|
||||
|
||||
isEligible := gaslessManager.IsEligibleForGasless(msgs)
|
||||
fmt.Printf("Transaction eligible for gasless: %v\n", isEligible)
|
||||
|
||||
// Estimate gas for gasless transaction
|
||||
gasNeeded := gaslessManager.EstimateGaslessGas(
|
||||
"/did.v1.MsgRegisterWebAuthnCredential",
|
||||
)
|
||||
fmt.Printf("Gas needed for gasless WebAuthn: %d\n", gasNeeded)
|
||||
```
|
||||
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## 6. Working with DID Module
|
||||
|
||||
Create and manage decentralized identities:
|
||||
|
||||
<Steps>
|
||||
<Step>
|
||||
### Create a DID Document
|
||||
|
||||
```go
|
||||
import (
|
||||
didtypes "github.com/sonr-io/sonr/x/did/types"
|
||||
)
|
||||
|
||||
// Create DID document
|
||||
didDoc := &didtypes.DidDocument{
|
||||
Id: "did:sonr:" + walletIdentity.Address,
|
||||
Controller: walletIdentity.Address,
|
||||
VerificationMethod: []*didtypes.VerificationMethod{
|
||||
{
|
||||
Id: "did:sonr:" + walletIdentity.Address + "#key-1",
|
||||
VerificationMethodKind: didtypes.VerificationMethodKind_Ed25519VerificationKey2020,
|
||||
Controller: "did:sonr:" + walletIdentity.Address,
|
||||
PublicKeyMultibase: "z6MkhaXgBZD...", // Your public key
|
||||
},
|
||||
},
|
||||
Service: []*didtypes.Service{
|
||||
{
|
||||
Id: "did:sonr:" + walletIdentity.Address + "#dwn",
|
||||
ServiceKind: didtypes.ServiceKind_DecentralizedWebNode,
|
||||
SingleEndpoint: "https://dwn.example.com",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// Create the message
|
||||
createDIDMsg, err := didClient.CreateDID(
|
||||
walletIdentity.Address,
|
||||
didDoc,
|
||||
)
|
||||
if err != nil {
|
||||
log.Fatal("Failed to create DID message:", err)
|
||||
}
|
||||
|
||||
// Add to transaction and broadcast
|
||||
txBuilder = txBuilder.
|
||||
ClearMessages().
|
||||
AddMessage(createDIDMsg).
|
||||
WithMemo("Create DID")
|
||||
|
||||
// Sign and broadcast as shown earlier
|
||||
```
|
||||
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## Next Steps
|
||||
|
||||
This quickstart has covered the fundamentals of the Sonr Go Client SDK:
|
||||
|
||||
- **Client Configuration**: Setting up connections and network configurations
|
||||
- **Key Management**: Creating and managing wallets with the keyring
|
||||
- **Querying**: Reading blockchain state and module data
|
||||
- **Transactions**: Building, signing, and broadcasting transactions
|
||||
- **Gas Estimation**: Calculating optimal gas limits and fees
|
||||
- **WebAuthn**: Gasless onboarding with WebAuthn credentials
|
||||
- **DID Module**: Creating decentralized identities
|
||||
|
||||
### Advanced Topics to Explore:
|
||||
|
||||
- **DWN Module**: Manage decentralized web nodes and data records
|
||||
- **Service Module**: Register and verify services with domain verification
|
||||
- **UCAN Integration**: Implement capability-based authorization
|
||||
- **Multi-signature**: Create and manage multi-sig accounts
|
||||
- **IBC Transfers**: Cross-chain token transfers
|
||||
- **Custom Modules**: Interact with your own custom modules
|
||||
|
||||
### Useful Resources:
|
||||
|
||||
- [Client SDK API Reference](https://pkg.go.dev/github.com/sonr-io/sonr/client)
|
||||
- [Cosmos SDK Documentation](https://docs.cosmos.network)
|
||||
- [Sonr GitHub Repository](https://github.com/sonr-io/sonr)
|
||||
@@ -1,190 +0,0 @@
|
||||
---
|
||||
title: Getting Started with ReactJS
|
||||
description: A quick start guide for building applications with Sonr using JavaScript and TypeScript
|
||||
sidebarTitle: React Quickstart
|
||||
icon: "react"
|
||||
---
|
||||
|
||||
This guide will show you how to set up a Node.js project with TypeScript and use the Sonr SDK to interact with the Sonr network.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- A local Sonr network running. See the [Validator Setup Guide](/quickstart/validators) for instructions
|
||||
- Node.js version 16 or higher
|
||||
- npm or yarn
|
||||
|
||||
## 1. Project Setup
|
||||
|
||||
<Steps>
|
||||
<Step>
|
||||
### Initialize a New Project
|
||||
|
||||
Create a new directory for your project and initialize it with npm:
|
||||
|
||||
```bash
|
||||
mkdir sonr-ts-quickstart
|
||||
cd sonr-ts-quickstart
|
||||
npm init -y
|
||||
```
|
||||
|
||||
</Step>
|
||||
|
||||
<Step>
|
||||
### Install Dependencies
|
||||
|
||||
Install the Sonr SDK and TypeScript:
|
||||
|
||||
```bash
|
||||
npm install @sonr/sdk typescript ts-node @types/node
|
||||
```
|
||||
|
||||
</Step>
|
||||
|
||||
<Step>
|
||||
### Configure TypeScript
|
||||
|
||||
Create a `tsconfig.json` file in your project root with the following configuration:
|
||||
|
||||
```json
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es2020",
|
||||
"module": "commonjs",
|
||||
"esModuleInterop": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"strict": true,
|
||||
"skipLibCheck": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## 2. Creating a Wallet
|
||||
|
||||
Now, let's create a new TypeScript file and add the logic to create a new Sonr wallet.
|
||||
|
||||
<Steps>
|
||||
<Step>
|
||||
### Create the Main File
|
||||
|
||||
Create a new file named `index.ts`.
|
||||
|
||||
</Step>
|
||||
|
||||
<Step>
|
||||
### Implement Wallet Creation
|
||||
|
||||
Add the following code to `index.ts` to create a new wallet and log its address and mnemonic:
|
||||
|
||||
```typescript
|
||||
import { Sonr } from "@sonr/sdk";
|
||||
|
||||
async function main() {
|
||||
console.log("Creating a new Sonr wallet...");
|
||||
|
||||
const sonr = new Sonr({ httpUrl: "http://localhost:1317" });
|
||||
const wallet = await sonr.createWallet();
|
||||
|
||||
console.log(`Wallet created!`);
|
||||
console.log(`Address: ${wallet.address}`);
|
||||
console.log(`Mnemonic: ${wallet.mnemonic}`);
|
||||
}
|
||||
|
||||
main().catch(console.error);
|
||||
```
|
||||
|
||||
<Note type="warning">
|
||||
**Important**: In a real application, you must store the mnemonic securely.
|
||||
Never expose it in client-side code.
|
||||
</Note>
|
||||
</Step>
|
||||
|
||||
<Step>
|
||||
### Run the Script
|
||||
|
||||
Execute the script using `ts-node`:
|
||||
|
||||
```bash
|
||||
npx ts-node index.ts
|
||||
```
|
||||
|
||||
You should see the new wallet's address and mnemonic printed to the console.
|
||||
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## 3. Querying the Blockchain
|
||||
|
||||
Let's query the blockchain to get the balance of our new wallet.
|
||||
|
||||
<Steps>
|
||||
<Step>
|
||||
### Get Account Balance
|
||||
|
||||
Modify your `index.ts` file to query the account balance after creating the wallet. You will need to fund this account from the localnet faucet for it to have a balance.
|
||||
|
||||
```typescript
|
||||
// ... after creating the wallet
|
||||
|
||||
console.log("Querying account balance...");
|
||||
|
||||
// The localnet validator has funds, so we'll use its address for the query
|
||||
const validatorAddress = "snr1..._validator_address_..."; // Replace with the actual validator address from your localnet
|
||||
const balance = await sonr.getAccountBalance(validatorAddress);
|
||||
|
||||
console.log(`Balance for ${validatorAddress}:`, balance);
|
||||
```
|
||||
|
||||
</Step>
|
||||
|
||||
<Step>
|
||||
### Run the Script Again
|
||||
|
||||
Run the script to see the account balance:
|
||||
|
||||
```bash
|
||||
npx ts-node index.ts
|
||||
```
|
||||
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## 4. Sending a Transaction
|
||||
|
||||
Finally, let's send a transaction from one account to another.
|
||||
|
||||
<Steps>
|
||||
<Step>
|
||||
### Implement Transaction Sending
|
||||
|
||||
For this step, you will need two wallets. You can create a second one using the same `createWallet` method. Ensure both wallets have funds from the localnet faucet.
|
||||
|
||||
```typescript
|
||||
// ... inside your main function
|
||||
|
||||
const wallet1 = await sonr.createWallet(); // Fund this from the faucet
|
||||
const wallet2 = await sonr.createWallet();
|
||||
|
||||
console.log(`Sending 1 SNR from ${wallet1.address} to ${wallet2.address}`);
|
||||
|
||||
const result = await wallet1.send({
|
||||
to: wallet2.address,
|
||||
amount: "1000000usnr", // 1 SNR
|
||||
});
|
||||
|
||||
console.log(`Transaction successful! TxHash: ${result.txhash}`);
|
||||
```
|
||||
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## Next Steps
|
||||
|
||||
This quickstart has shown you the basics of interacting with the Sonr network using our TypeScript SDK. You can now explore more advanced topics:
|
||||
|
||||
- **Service Registration**: Register your application as a trusted service
|
||||
- **UCAN Authorization**: Implement capability-based permissions
|
||||
- **Smart Contract Interaction**: Call and query smart contracts on the Sonr network
|
||||
|
||||
@@ -1,155 +0,0 @@
|
||||
---
|
||||
title: "DWN Plugin Architecture"
|
||||
description: "Deep dive into the Decentralized Web Node (DWN) plugin system and integration"
|
||||
sidebarTitle: "WASM Architecture"
|
||||
icon: "puzzle"
|
||||
---
|
||||
|
||||
# DWN Plugin Architecture
|
||||
|
||||
The Sonr project implements a flexible and secure plugin system for Decentralized Web Nodes (DWN), enabling modular and extensible functionality.
|
||||
|
||||
## Overview
|
||||
|
||||
The plugin architecture is designed to:
|
||||
|
||||
- Support dynamic loading of WebAssembly (WASM) plugins
|
||||
- Provide a standardized interface for plugin interactions
|
||||
- Enable secure, isolated execution of plugins
|
||||
|
||||
## Core Components
|
||||
|
||||
### Plugin Manager
|
||||
|
||||
The `PluginManager` manages plugin lifecycle and interactions:
|
||||
|
||||
```go
|
||||
type PluginManager struct {
|
||||
plugins map[string]Plugin
|
||||
actors map[string]Actor
|
||||
}
|
||||
|
||||
type Plugin interface {
|
||||
Initialize(config map[string]any) error
|
||||
Execute(method string, payload []byte) ([]byte, error)
|
||||
Close() error
|
||||
}
|
||||
```
|
||||
|
||||
### Plugin Configuration
|
||||
|
||||
Plugins are configured through a structured configuration:
|
||||
|
||||
```go
|
||||
type PluginConfig struct {
|
||||
ID string // Unique plugin identifier
|
||||
Type string // Plugin type (e.g., "motor", "crypto")
|
||||
Path string // WASM module path
|
||||
Environment map[string]any // Plugin-specific environment variables
|
||||
}
|
||||
```
|
||||
|
||||
## Loading and Initializing Plugins
|
||||
|
||||
### Basic Plugin Loading
|
||||
|
||||
```go
|
||||
func (pm *PluginManager) LoadPlugin(config PluginConfig) error {
|
||||
// Load WASM module
|
||||
module, err := extism.Load(config.Path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Initialize plugin
|
||||
plugin := &WASMPlugin{
|
||||
module: module,
|
||||
config: config,
|
||||
}
|
||||
|
||||
// Store in plugin registry
|
||||
pm.plugins[config.ID] = plugin
|
||||
}
|
||||
```
|
||||
|
||||
### Actor-Based Plugin Management
|
||||
|
||||
```go
|
||||
func (pm *PluginManager) CreateActor(pluginID string) (*Actor, error) {
|
||||
plugin, exists := pm.plugins[pluginID]
|
||||
if !exists {
|
||||
return nil, errors.New("plugin not found")
|
||||
}
|
||||
|
||||
actor := NewActor(plugin)
|
||||
pm.actors[actor.ID] = actor
|
||||
|
||||
return actor, nil
|
||||
}
|
||||
```
|
||||
|
||||
## Plugin Execution Workflow
|
||||
|
||||
1. Plugin is loaded from WASM module
|
||||
2. Configuration is applied
|
||||
3. Plugin is initialized
|
||||
4. Specific methods can be invoked through a standardized interface
|
||||
|
||||
### Example Plugin Execution
|
||||
|
||||
```go
|
||||
func ExecutePluginMethod(pluginID, method string, payload []byte) ([]byte, error) {
|
||||
plugin := pluginManager.plugins[pluginID]
|
||||
return plugin.Execute(method, payload)
|
||||
}
|
||||
```
|
||||
|
||||
## Configuration and Environment
|
||||
|
||||
### Plugin Environment Variables
|
||||
|
||||
```json
|
||||
{
|
||||
"motor_plugin": {
|
||||
"enclave_config": { ... },
|
||||
"chain_id": "sonr-testnet-1",
|
||||
"log_level": "debug"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Error Handling and Logging
|
||||
|
||||
```go
|
||||
type PluginError struct {
|
||||
Code string
|
||||
Message string
|
||||
Details map[string]any
|
||||
}
|
||||
```
|
||||
|
||||
## Security Considerations
|
||||
|
||||
- WASM plugins run in an isolated sandbox
|
||||
- Limited access to system resources
|
||||
- Runtime restrictions prevent malicious behavior
|
||||
- Cryptographic verification of plugin modules
|
||||
|
||||
## Plugin Types
|
||||
|
||||
1. **Crypto Plugins**: Cryptographic operations
|
||||
2. **Motor Plugins**: MPC and token management
|
||||
3. **DID Plugins**: Decentralized Identity operations
|
||||
4. **Custom Plugins**: Application-specific extensions
|
||||
|
||||
## Best Practices
|
||||
|
||||
- Keep plugins small and focused
|
||||
- Use standardized interfaces
|
||||
- Implement comprehensive error handling
|
||||
- Validate all plugin inputs
|
||||
- Monitor plugin performance
|
||||
|
||||
## Advanced Configuration
|
||||
|
||||
For advanced plugin configuration and deployment, refer to the [PDK Configuration Guide](/blockchain/modules/dwn/configuration).
|
||||
@@ -1,173 +0,0 @@
|
||||
---
|
||||
title: "@sonr.io/ui"
|
||||
sidebarTitle: "@sonr.io/ui"
|
||||
description: "A package for Sonr's centralized shadcn/ui component library"
|
||||
icon: "palette"
|
||||
---
|
||||
|
||||
# @sonr.io/ui
|
||||
|
||||
## Overview
|
||||
|
||||
The `@sonr.io/ui` package serves as our centralized shadcn/ui component library, providing a consistent and accessible design system across Sonr's ecosystem. Leveraging the power of shadcn/ui, we've created a fully customizable and type-safe component library with a primary color of `#17c2ff`.
|
||||
|
||||
<Callout type="info">
|
||||
Our UI package is built to provide maximum flexibility while maintaining
|
||||
strict design consistency.
|
||||
</Callout>
|
||||
|
||||
## Component Migration Strategy
|
||||
|
||||
### Before: Custom Button Component
|
||||
|
||||
Previously, our Button component relied on manual variant classes and custom implementations:
|
||||
|
||||
```tsx
|
||||
// Old Implementation
|
||||
const Button = ({ variant, className, ...props }) => {
|
||||
const variantClasses = {
|
||||
primary: "bg-blue-500 text-white",
|
||||
secondary: "bg-gray-200 text-black",
|
||||
// Multiple manual variant definitions
|
||||
};
|
||||
|
||||
return (
|
||||
<button className={`${variantClasses[variant]} ${className}`} {...props} />
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
### After: Shadcn Button Implementation
|
||||
|
||||
Our new implementation uses `cva` (class-variance-authority) and the `cn` utility for robust variant management:
|
||||
|
||||
```tsx
|
||||
// New Implementation
|
||||
import { buttonVariants } from "@sonr.io/ui/components/ui/button";
|
||||
import { cn } from "@sonr.io/ui/lib/utils";
|
||||
|
||||
const Button = ({
|
||||
variant = "default",
|
||||
size = "default",
|
||||
className,
|
||||
...props
|
||||
}) => {
|
||||
return (
|
||||
<button
|
||||
className={cn(buttonVariants({ variant, size }), className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
<Callout type="success">
|
||||
Key Improvements: - Type-safe variant management - Enhanced accessibility -
|
||||
Consistent theming - Reduced bundle size
|
||||
</Callout>
|
||||
|
||||
## Theme Configuration
|
||||
|
||||
### Color System
|
||||
|
||||
Our primary theme color is `#17c2ff`, defined in HSL format for maximum flexibility:
|
||||
|
||||
```css
|
||||
:root {
|
||||
--primary-h: 200; /* Hue */
|
||||
--primary-s: 100%; /* Saturation */
|
||||
--primary-l: 59%; /* Lightness */
|
||||
--primary: hsl(var(--primary-h), var(--primary-s), var(--primary-l));
|
||||
}
|
||||
```
|
||||
|
||||
### CSS Variables Structure
|
||||
|
||||
```css
|
||||
:root {
|
||||
--background: 0 0% 100%;
|
||||
--foreground: 240 10% 3.9%;
|
||||
--primary: 200 100% 59%;
|
||||
--primary-foreground: 210 40% 98%;
|
||||
--secondary: 220 14.3% 95.9%;
|
||||
--secondary-foreground: 220.9 39.3% 11%;
|
||||
/* Additional theme variables */
|
||||
}
|
||||
```
|
||||
|
||||
## Usage Guide
|
||||
|
||||
### Importing Components
|
||||
|
||||
Import components directly from the `@sonr.io/ui` package:
|
||||
|
||||
```tsx
|
||||
import { Button } from "@sonr.io/ui/components/ui/button";
|
||||
import { Input } from "@sonr.io/ui/components/ui/input";
|
||||
```
|
||||
|
||||
### Adding New Components
|
||||
|
||||
Use the shadcn CLI within the `packages/ui` directory:
|
||||
|
||||
```bash
|
||||
# Navigate to packages/ui
|
||||
cd packages/ui
|
||||
|
||||
# Add a new component
|
||||
npx shadcn-ui@latest add button
|
||||
```
|
||||
|
||||
<Callout type="warning">
|
||||
Always add components from the `packages/ui` directory to maintain our
|
||||
centralized component management.
|
||||
</Callout>
|
||||
|
||||
## Architecture Patterns
|
||||
|
||||
### Monorepo Structure
|
||||
|
||||
```
|
||||
sonr/
|
||||
├── packages/
|
||||
│ └── ui/
|
||||
│ ├── components/
|
||||
│ │ └── ui/
|
||||
│ │ ├── button.tsx
|
||||
│ │ ├── input.tsx
|
||||
│ │ └── ...
|
||||
│ ├── lib/
|
||||
│ │ └── utils.ts
|
||||
│ └── styles/
|
||||
│ └── globals.css
|
||||
```
|
||||
|
||||
### Key Principles
|
||||
|
||||
- **Single Source of Truth**: All UI components live in `packages/ui`
|
||||
- **No Local `components.json`**: Centralized configuration
|
||||
- **Turbo-powered Build Pipeline**: Efficient component compilation
|
||||
|
||||
## Global Styles Integration
|
||||
|
||||
In your application's main entry point:
|
||||
|
||||
```tsx
|
||||
import "@sonr.io/ui/styles/globals.css";
|
||||
|
||||
function MyApp({ Component, pageProps }) {
|
||||
return <Component {...pageProps} />;
|
||||
}
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. Always use the centralized components from `@sonr.io/ui`
|
||||
2. Prefer `cn()` utility for dynamic className composition
|
||||
3. Leverage TypeScript for type-safe component usage
|
||||
4. Use CSS variables for theming consistency
|
||||
|
||||
<Callout type="tip">
|
||||
Remember: Our UI library is designed to be both flexible and consistent. When
|
||||
in doubt, refer to the components in `@sonr.io/ui`.
|
||||
</Callout>
|
||||
@@ -1,173 +0,0 @@
|
||||
---
|
||||
title: "@sonr.io/ui"
|
||||
sidebarTitle: "@sonr.io/ui"
|
||||
description: "A package for Sonr's centralized shadcn/ui component library"
|
||||
icon: "palette"
|
||||
---
|
||||
|
||||
# @sonr.io/ui
|
||||
|
||||
## Overview
|
||||
|
||||
The `@sonr.io/ui` package serves as our centralized shadcn/ui component library, providing a consistent and accessible design system across Sonr's ecosystem. Leveraging the power of shadcn/ui, we've created a fully customizable and type-safe component library with a primary color of `#17c2ff`.
|
||||
|
||||
<Callout type="info">
|
||||
Our UI package is built to provide maximum flexibility while maintaining
|
||||
strict design consistency.
|
||||
</Callout>
|
||||
|
||||
## Component Migration Strategy
|
||||
|
||||
### Before: Custom Button Component
|
||||
|
||||
Previously, our Button component relied on manual variant classes and custom implementations:
|
||||
|
||||
```tsx
|
||||
// Old Implementation
|
||||
const Button = ({ variant, className, ...props }) => {
|
||||
const variantClasses = {
|
||||
primary: "bg-blue-500 text-white",
|
||||
secondary: "bg-gray-200 text-black",
|
||||
// Multiple manual variant definitions
|
||||
};
|
||||
|
||||
return (
|
||||
<button className={`${variantClasses[variant]} ${className}`} {...props} />
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
### After: Shadcn Button Implementation
|
||||
|
||||
Our new implementation uses `cva` (class-variance-authority) and the `cn` utility for robust variant management:
|
||||
|
||||
```tsx
|
||||
// New Implementation
|
||||
import { buttonVariants } from "@sonr.io/ui/components/ui/button";
|
||||
import { cn } from "@sonr.io/ui/lib/utils";
|
||||
|
||||
const Button = ({
|
||||
variant = "default",
|
||||
size = "default",
|
||||
className,
|
||||
...props
|
||||
}) => {
|
||||
return (
|
||||
<button
|
||||
className={cn(buttonVariants({ variant, size }), className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
<Callout type="success">
|
||||
Key Improvements: - Type-safe variant management - Enhanced accessibility -
|
||||
Consistent theming - Reduced bundle size
|
||||
</Callout>
|
||||
|
||||
## Theme Configuration
|
||||
|
||||
### Color System
|
||||
|
||||
Our primary theme color is `#17c2ff`, defined in HSL format for maximum flexibility:
|
||||
|
||||
```css
|
||||
:root {
|
||||
--primary-h: 200; /* Hue */
|
||||
--primary-s: 100%; /* Saturation */
|
||||
--primary-l: 59%; /* Lightness */
|
||||
--primary: hsl(var(--primary-h), var(--primary-s), var(--primary-l));
|
||||
}
|
||||
```
|
||||
|
||||
### CSS Variables Structure
|
||||
|
||||
```css
|
||||
:root {
|
||||
--background: 0 0% 100%;
|
||||
--foreground: 240 10% 3.9%;
|
||||
--primary: 200 100% 59%;
|
||||
--primary-foreground: 210 40% 98%;
|
||||
--secondary: 220 14.3% 95.9%;
|
||||
--secondary-foreground: 220.9 39.3% 11%;
|
||||
/* Additional theme variables */
|
||||
}
|
||||
```
|
||||
|
||||
## Usage Guide
|
||||
|
||||
### Importing Components
|
||||
|
||||
Import components directly from the `@sonr.io/ui` package:
|
||||
|
||||
```tsx
|
||||
import { Button } from "@sonr.io/ui/components/ui/button";
|
||||
import { Input } from "@sonr.io/ui/components/ui/input";
|
||||
```
|
||||
|
||||
### Adding New Components
|
||||
|
||||
Use the shadcn CLI within the `packages/ui` directory:
|
||||
|
||||
```bash
|
||||
# Navigate to packages/ui
|
||||
cd packages/ui
|
||||
|
||||
# Add a new component
|
||||
npx shadcn-ui@latest add button
|
||||
```
|
||||
|
||||
<Callout type="warning">
|
||||
Always add components from the `packages/ui` directory to maintain our
|
||||
centralized component management.
|
||||
</Callout>
|
||||
|
||||
## Architecture Patterns
|
||||
|
||||
### Monorepo Structure
|
||||
|
||||
```
|
||||
sonr/
|
||||
├── packages/
|
||||
│ └── ui/
|
||||
│ ├── components/
|
||||
│ │ └── ui/
|
||||
│ │ ├── button.tsx
|
||||
│ │ ├── input.tsx
|
||||
│ │ └── ...
|
||||
│ ├── lib/
|
||||
│ │ └── utils.ts
|
||||
│ └── styles/
|
||||
│ └── globals.css
|
||||
```
|
||||
|
||||
### Key Principles
|
||||
|
||||
- **Single Source of Truth**: All UI components live in `packages/ui`
|
||||
- **No Local `components.json`**: Centralized configuration
|
||||
- **Turbo-powered Build Pipeline**: Efficient component compilation
|
||||
|
||||
## Global Styles Integration
|
||||
|
||||
In your application's main entry point:
|
||||
|
||||
```tsx
|
||||
import "@sonr.io/ui/styles/globals.css";
|
||||
|
||||
function MyApp({ Component, pageProps }) {
|
||||
return <Component {...pageProps} />;
|
||||
}
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. Always use the centralized components from `@sonr.io/ui`
|
||||
2. Prefer `cn()` utility for dynamic className composition
|
||||
3. Leverage TypeScript for type-safe component usage
|
||||
4. Use CSS variables for theming consistency
|
||||
|
||||
<Callout type="tip">
|
||||
Remember: Our UI library is designed to be both flexible and consistent. When
|
||||
in doubt, refer to the components in `@sonr.io/ui`.
|
||||
</Callout>
|
||||
@@ -1,173 +0,0 @@
|
||||
---
|
||||
title: "@sonr.io/ui"
|
||||
sidebarTitle: "@sonr.io/ui"
|
||||
description: "A package for Sonr's centralized shadcn/ui component library"
|
||||
icon: "palette"
|
||||
---
|
||||
|
||||
# @sonr.io/ui
|
||||
|
||||
## Overview
|
||||
|
||||
The `@sonr.io/ui` package serves as our centralized shadcn/ui component library, providing a consistent and accessible design system across Sonr's ecosystem. Leveraging the power of shadcn/ui, we've created a fully customizable and type-safe component library with a primary color of `#17c2ff`.
|
||||
|
||||
<Callout type="info">
|
||||
Our UI package is built to provide maximum flexibility while maintaining
|
||||
strict design consistency.
|
||||
</Callout>
|
||||
|
||||
## Component Migration Strategy
|
||||
|
||||
### Before: Custom Button Component
|
||||
|
||||
Previously, our Button component relied on manual variant classes and custom implementations:
|
||||
|
||||
```tsx
|
||||
// Old Implementation
|
||||
const Button = ({ variant, className, ...props }) => {
|
||||
const variantClasses = {
|
||||
primary: "bg-blue-500 text-white",
|
||||
secondary: "bg-gray-200 text-black",
|
||||
// Multiple manual variant definitions
|
||||
};
|
||||
|
||||
return (
|
||||
<button className={`${variantClasses[variant]} ${className}`} {...props} />
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
### After: Shadcn Button Implementation
|
||||
|
||||
Our new implementation uses `cva` (class-variance-authority) and the `cn` utility for robust variant management:
|
||||
|
||||
```tsx
|
||||
// New Implementation
|
||||
import { buttonVariants } from "@sonr.io/ui/components/ui/button";
|
||||
import { cn } from "@sonr.io/ui/lib/utils";
|
||||
|
||||
const Button = ({
|
||||
variant = "default",
|
||||
size = "default",
|
||||
className,
|
||||
...props
|
||||
}) => {
|
||||
return (
|
||||
<button
|
||||
className={cn(buttonVariants({ variant, size }), className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
<Callout type="success">
|
||||
Key Improvements: - Type-safe variant management - Enhanced accessibility -
|
||||
Consistent theming - Reduced bundle size
|
||||
</Callout>
|
||||
|
||||
## Theme Configuration
|
||||
|
||||
### Color System
|
||||
|
||||
Our primary theme color is `#17c2ff`, defined in HSL format for maximum flexibility:
|
||||
|
||||
```css
|
||||
:root {
|
||||
--primary-h: 200; /* Hue */
|
||||
--primary-s: 100%; /* Saturation */
|
||||
--primary-l: 59%; /* Lightness */
|
||||
--primary: hsl(var(--primary-h), var(--primary-s), var(--primary-l));
|
||||
}
|
||||
```
|
||||
|
||||
### CSS Variables Structure
|
||||
|
||||
```css
|
||||
:root {
|
||||
--background: 0 0% 100%;
|
||||
--foreground: 240 10% 3.9%;
|
||||
--primary: 200 100% 59%;
|
||||
--primary-foreground: 210 40% 98%;
|
||||
--secondary: 220 14.3% 95.9%;
|
||||
--secondary-foreground: 220.9 39.3% 11%;
|
||||
/* Additional theme variables */
|
||||
}
|
||||
```
|
||||
|
||||
## Usage Guide
|
||||
|
||||
### Importing Components
|
||||
|
||||
Import components directly from the `@sonr.io/ui` package:
|
||||
|
||||
```tsx
|
||||
import { Button } from "@sonr.io/ui/components/ui/button";
|
||||
import { Input } from "@sonr.io/ui/components/ui/input";
|
||||
```
|
||||
|
||||
### Adding New Components
|
||||
|
||||
Use the shadcn CLI within the `packages/ui` directory:
|
||||
|
||||
```bash
|
||||
# Navigate to packages/ui
|
||||
cd packages/ui
|
||||
|
||||
# Add a new component
|
||||
npx shadcn-ui@latest add button
|
||||
```
|
||||
|
||||
<Callout type="warning">
|
||||
Always add components from the `packages/ui` directory to maintain our
|
||||
centralized component management.
|
||||
</Callout>
|
||||
|
||||
## Architecture Patterns
|
||||
|
||||
### Monorepo Structure
|
||||
|
||||
```
|
||||
sonr/
|
||||
├── packages/
|
||||
│ └── ui/
|
||||
│ ├── components/
|
||||
│ │ └── ui/
|
||||
│ │ ├── button.tsx
|
||||
│ │ ├── input.tsx
|
||||
│ │ └── ...
|
||||
│ ├── lib/
|
||||
│ │ └── utils.ts
|
||||
│ └── styles/
|
||||
│ └── globals.css
|
||||
```
|
||||
|
||||
### Key Principles
|
||||
|
||||
- **Single Source of Truth**: All UI components live in `packages/ui`
|
||||
- **No Local `components.json`**: Centralized configuration
|
||||
- **Turbo-powered Build Pipeline**: Efficient component compilation
|
||||
|
||||
## Global Styles Integration
|
||||
|
||||
In your application's main entry point:
|
||||
|
||||
```tsx
|
||||
import "@sonr.io/ui/styles/globals.css";
|
||||
|
||||
function MyApp({ Component, pageProps }) {
|
||||
return <Component {...pageProps} />;
|
||||
}
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. Always use the centralized components from `@sonr.io/ui`
|
||||
2. Prefer `cn()` utility for dynamic className composition
|
||||
3. Leverage TypeScript for type-safe component usage
|
||||
4. Use CSS variables for theming consistency
|
||||
|
||||
<Callout type="tip">
|
||||
Remember: Our UI library is designed to be both flexible and consistent. When
|
||||
in doubt, refer to the components in `@sonr.io/ui`.
|
||||
</Callout>
|
||||
@@ -1,173 +0,0 @@
|
||||
---
|
||||
title: "@sonr.io/ui"
|
||||
sidebarTitle: "@sonr.io/ui"
|
||||
description: "A package for Sonr's centralized shadcn/ui component library"
|
||||
icon: "palette"
|
||||
---
|
||||
|
||||
# @sonr.io/ui
|
||||
|
||||
## Overview
|
||||
|
||||
The `@sonr.io/ui` package serves as our centralized shadcn/ui component library, providing a consistent and accessible design system across Sonr's ecosystem. Leveraging the power of shadcn/ui, we've created a fully customizable and type-safe component library with a primary color of `#17c2ff`.
|
||||
|
||||
<Callout type="info">
|
||||
Our UI package is built to provide maximum flexibility while maintaining
|
||||
strict design consistency.
|
||||
</Callout>
|
||||
|
||||
## Component Migration Strategy
|
||||
|
||||
### Before: Custom Button Component
|
||||
|
||||
Previously, our Button component relied on manual variant classes and custom implementations:
|
||||
|
||||
```tsx
|
||||
// Old Implementation
|
||||
const Button = ({ variant, className, ...props }) => {
|
||||
const variantClasses = {
|
||||
primary: "bg-blue-500 text-white",
|
||||
secondary: "bg-gray-200 text-black",
|
||||
// Multiple manual variant definitions
|
||||
};
|
||||
|
||||
return (
|
||||
<button className={`${variantClasses[variant]} ${className}`} {...props} />
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
### After: Shadcn Button Implementation
|
||||
|
||||
Our new implementation uses `cva` (class-variance-authority) and the `cn` utility for robust variant management:
|
||||
|
||||
```tsx
|
||||
// New Implementation
|
||||
import { buttonVariants } from "@sonr.io/ui/components/ui/button";
|
||||
import { cn } from "@sonr.io/ui/lib/utils";
|
||||
|
||||
const Button = ({
|
||||
variant = "default",
|
||||
size = "default",
|
||||
className,
|
||||
...props
|
||||
}) => {
|
||||
return (
|
||||
<button
|
||||
className={cn(buttonVariants({ variant, size }), className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
<Callout type="success">
|
||||
Key Improvements: - Type-safe variant management - Enhanced accessibility -
|
||||
Consistent theming - Reduced bundle size
|
||||
</Callout>
|
||||
|
||||
## Theme Configuration
|
||||
|
||||
### Color System
|
||||
|
||||
Our primary theme color is `#17c2ff`, defined in HSL format for maximum flexibility:
|
||||
|
||||
```css
|
||||
:root {
|
||||
--primary-h: 200; /* Hue */
|
||||
--primary-s: 100%; /* Saturation */
|
||||
--primary-l: 59%; /* Lightness */
|
||||
--primary: hsl(var(--primary-h), var(--primary-s), var(--primary-l));
|
||||
}
|
||||
```
|
||||
|
||||
### CSS Variables Structure
|
||||
|
||||
```css
|
||||
:root {
|
||||
--background: 0 0% 100%;
|
||||
--foreground: 240 10% 3.9%;
|
||||
--primary: 200 100% 59%;
|
||||
--primary-foreground: 210 40% 98%;
|
||||
--secondary: 220 14.3% 95.9%;
|
||||
--secondary-foreground: 220.9 39.3% 11%;
|
||||
/* Additional theme variables */
|
||||
}
|
||||
```
|
||||
|
||||
## Usage Guide
|
||||
|
||||
### Importing Components
|
||||
|
||||
Import components directly from the `@sonr.io/ui` package:
|
||||
|
||||
```tsx
|
||||
import { Button } from "@sonr.io/ui/components/ui/button";
|
||||
import { Input } from "@sonr.io/ui/components/ui/input";
|
||||
```
|
||||
|
||||
### Adding New Components
|
||||
|
||||
Use the shadcn CLI within the `packages/ui` directory:
|
||||
|
||||
```bash
|
||||
# Navigate to packages/ui
|
||||
cd packages/ui
|
||||
|
||||
# Add a new component
|
||||
npx shadcn-ui@latest add button
|
||||
```
|
||||
|
||||
<Callout type="warning">
|
||||
Always add components from the `packages/ui` directory to maintain our
|
||||
centralized component management.
|
||||
</Callout>
|
||||
|
||||
## Architecture Patterns
|
||||
|
||||
### Monorepo Structure
|
||||
|
||||
```
|
||||
sonr/
|
||||
├── packages/
|
||||
│ └── ui/
|
||||
│ ├── components/
|
||||
│ │ └── ui/
|
||||
│ │ ├── button.tsx
|
||||
│ │ ├── input.tsx
|
||||
│ │ └── ...
|
||||
│ ├── lib/
|
||||
│ │ └── utils.ts
|
||||
│ └── styles/
|
||||
│ └── globals.css
|
||||
```
|
||||
|
||||
### Key Principles
|
||||
|
||||
- **Single Source of Truth**: All UI components live in `packages/ui`
|
||||
- **No Local `components.json`**: Centralized configuration
|
||||
- **Turbo-powered Build Pipeline**: Efficient component compilation
|
||||
|
||||
## Global Styles Integration
|
||||
|
||||
In your application's main entry point:
|
||||
|
||||
```tsx
|
||||
import "@sonr.io/ui/styles/globals.css";
|
||||
|
||||
function MyApp({ Component, pageProps }) {
|
||||
return <Component {...pageProps} />;
|
||||
}
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. Always use the centralized components from `@sonr.io/ui`
|
||||
2. Prefer `cn()` utility for dynamic className composition
|
||||
3. Leverage TypeScript for type-safe component usage
|
||||
4. Use CSS variables for theming consistency
|
||||
|
||||
<Callout type="tip">
|
||||
Remember: Our UI library is designed to be both flexible and consistent. When
|
||||
in doubt, refer to the components in `@sonr.io/ui`.
|
||||
</Callout>
|
||||
@@ -1,173 +0,0 @@
|
||||
---
|
||||
title: "@sonr.io/ui"
|
||||
sidebarTitle: "@sonr.io/ui"
|
||||
description: "A package for Sonr's centralized shadcn/ui component library"
|
||||
icon: "palette"
|
||||
---
|
||||
|
||||
# @sonr.io/ui
|
||||
|
||||
## Overview
|
||||
|
||||
The `@sonr.io/ui` package serves as our centralized shadcn/ui component library, providing a consistent and accessible design system across Sonr's ecosystem. Leveraging the power of shadcn/ui, we've created a fully customizable and type-safe component library with a primary color of `#17c2ff`.
|
||||
|
||||
<Callout type="info">
|
||||
Our UI package is built to provide maximum flexibility while maintaining
|
||||
strict design consistency.
|
||||
</Callout>
|
||||
|
||||
## Component Migration Strategy
|
||||
|
||||
### Before: Custom Button Component
|
||||
|
||||
Previously, our Button component relied on manual variant classes and custom implementations:
|
||||
|
||||
```tsx
|
||||
// Old Implementation
|
||||
const Button = ({ variant, className, ...props }) => {
|
||||
const variantClasses = {
|
||||
primary: "bg-blue-500 text-white",
|
||||
secondary: "bg-gray-200 text-black",
|
||||
// Multiple manual variant definitions
|
||||
};
|
||||
|
||||
return (
|
||||
<button className={`${variantClasses[variant]} ${className}`} {...props} />
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
### After: Shadcn Button Implementation
|
||||
|
||||
Our new implementation uses `cva` (class-variance-authority) and the `cn` utility for robust variant management:
|
||||
|
||||
```tsx
|
||||
// New Implementation
|
||||
import { buttonVariants } from "@sonr.io/ui/components/ui/button";
|
||||
import { cn } from "@sonr.io/ui/lib/utils";
|
||||
|
||||
const Button = ({
|
||||
variant = "default",
|
||||
size = "default",
|
||||
className,
|
||||
...props
|
||||
}) => {
|
||||
return (
|
||||
<button
|
||||
className={cn(buttonVariants({ variant, size }), className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
<Callout type="success">
|
||||
Key Improvements: - Type-safe variant management - Enhanced accessibility -
|
||||
Consistent theming - Reduced bundle size
|
||||
</Callout>
|
||||
|
||||
## Theme Configuration
|
||||
|
||||
### Color System
|
||||
|
||||
Our primary theme color is `#17c2ff`, defined in HSL format for maximum flexibility:
|
||||
|
||||
```css
|
||||
:root {
|
||||
--primary-h: 200; /* Hue */
|
||||
--primary-s: 100%; /* Saturation */
|
||||
--primary-l: 59%; /* Lightness */
|
||||
--primary: hsl(var(--primary-h), var(--primary-s), var(--primary-l));
|
||||
}
|
||||
```
|
||||
|
||||
### CSS Variables Structure
|
||||
|
||||
```css
|
||||
:root {
|
||||
--background: 0 0% 100%;
|
||||
--foreground: 240 10% 3.9%;
|
||||
--primary: 200 100% 59%;
|
||||
--primary-foreground: 210 40% 98%;
|
||||
--secondary: 220 14.3% 95.9%;
|
||||
--secondary-foreground: 220.9 39.3% 11%;
|
||||
/* Additional theme variables */
|
||||
}
|
||||
```
|
||||
|
||||
## Usage Guide
|
||||
|
||||
### Importing Components
|
||||
|
||||
Import components directly from the `@sonr.io/ui` package:
|
||||
|
||||
```tsx
|
||||
import { Button } from "@sonr.io/ui/components/ui/button";
|
||||
import { Input } from "@sonr.io/ui/components/ui/input";
|
||||
```
|
||||
|
||||
### Adding New Components
|
||||
|
||||
Use the shadcn CLI within the `packages/ui` directory:
|
||||
|
||||
```bash
|
||||
# Navigate to packages/ui
|
||||
cd packages/ui
|
||||
|
||||
# Add a new component
|
||||
npx shadcn-ui@latest add button
|
||||
```
|
||||
|
||||
<Callout type="warning">
|
||||
Always add components from the `packages/ui` directory to maintain our
|
||||
centralized component management.
|
||||
</Callout>
|
||||
|
||||
## Architecture Patterns
|
||||
|
||||
### Monorepo Structure
|
||||
|
||||
```
|
||||
sonr/
|
||||
├── packages/
|
||||
│ └── ui/
|
||||
│ ├── components/
|
||||
│ │ └── ui/
|
||||
│ │ ├── button.tsx
|
||||
│ │ ├── input.tsx
|
||||
│ │ └── ...
|
||||
│ ├── lib/
|
||||
│ │ └── utils.ts
|
||||
│ └── styles/
|
||||
│ └── globals.css
|
||||
```
|
||||
|
||||
### Key Principles
|
||||
|
||||
- **Single Source of Truth**: All UI components live in `packages/ui`
|
||||
- **No Local `components.json`**: Centralized configuration
|
||||
- **Turbo-powered Build Pipeline**: Efficient component compilation
|
||||
|
||||
## Global Styles Integration
|
||||
|
||||
In your application's main entry point:
|
||||
|
||||
```tsx
|
||||
import "@sonr.io/ui/styles/globals.css";
|
||||
|
||||
function MyApp({ Component, pageProps }) {
|
||||
return <Component {...pageProps} />;
|
||||
}
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. Always use the centralized components from `@sonr.io/ui`
|
||||
2. Prefer `cn()` utility for dynamic className composition
|
||||
3. Leverage TypeScript for type-safe component usage
|
||||
4. Use CSS variables for theming consistency
|
||||
|
||||
<Callout type="tip">
|
||||
Remember: Our UI library is designed to be both flexible and consistent. When
|
||||
in doubt, refer to the components in `@sonr.io/ui`.
|
||||
</Callout>
|
||||
Reference in New Issue
Block a user