@coder/mux-md-client
v0.1.0-main.17
Published
Client library for mux.md encrypted file sharing with signature support
Downloads
3,497
Readme
@coder/mux-md-client
Client library for mux.md encrypted file sharing with signature support.
Installation
npm install @coder/mux-md-client
# or
bun add @coder/mux-md-clientFeatures
- End-to-end encryption — AES-256-GCM with HKDF key derivation
- Message signing — Ed25519 and ECDSA (P-256, P-384, P-521) support
- SSH key format — Parse and use standard OpenSSH public keys
- Zero-knowledge — Server never sees plaintext content or signatures
- Minimal dependencies — Only
@noble/*for cryptographic primitives
Usage
Upload content
import { upload } from '@coder/mux-md-client';
const content = new TextEncoder().encode('# Hello World');
const result = await upload(
content,
{ name: 'message.md', type: 'text/markdown', size: content.length },
{ expiresAt: Date.now() + 7 * 24 * 60 * 60 * 1000 } // 7 days
);
console.log(result.url); // https://mux.md/Ab3Xy#key...
console.log(result.mutateKey); // Store for deletion/expiration updatesDownload content
import { download } from '@coder/mux-md-client';
const { data, info, signature } = await download('https://mux.md/Ab3Xy#key...');
console.log(new TextDecoder().decode(data));
if (signature) {
console.log('Signed by:', signature.publicKey);
}Upload with signature
import { upload, createSignatureEnvelope } from '@coder/mux-md-client';
const content = new TextEncoder().encode('# Signed Message');
// Create signature from your SSH key
const signature = await createSignatureEnvelope(
content,
privateKey, // 32-byte Ed25519 private key
'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAA...', // Your public key
{ email: '[email protected]' }
);
const result = await upload(
content,
{ name: 'signed.md', type: 'text/markdown', size: content.length },
{ signature }
);Verify signatures
import { parsePublicKey, verifySignature, base64Decode } from '@coder/mux-md-client';
const parsedKey = parsePublicKey('ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAA...');
const sigBytes = base64Decode(signature.sig);
const messageBytes = new TextEncoder().encode(content);
const valid = await verifySignature(parsedKey, messageBytes, sigBytes);Delete or update expiration
import { deleteFile, setExpiration } from '@coder/mux-md-client';
// Delete file
await deleteFile(result.id, result.mutateKey);
// Update expiration
await setExpiration(result.id, result.mutateKey, Date.now() + 30 * 24 * 60 * 60 * 1000);
// Remove expiration
await setExpiration(result.id, result.mutateKey, 'never');API Reference
Client Operations
| Function | Description |
|----------|-------------|
| upload(data, fileInfo, options?) | Encrypt and upload content |
| download(url, key?, options?) | Download and decrypt content |
| getMeta(url, key?, options?) | Get file metadata without downloading |
| deleteFile(id, mutateKey, options?) | Delete a file |
| setExpiration(id, mutateKey, expiresAt, options?) | Update file expiration |
| parseUrl(url) | Parse mux.md URL into id + key |
| buildUrl(id, key, baseUrl?) | Build mux.md URL from components |
Signing
| Function | Description |
|----------|-------------|
| createSignatureEnvelope(content, privateKey, publicKey, options?) | Create a signature envelope for upload |
| signEd25519(message, privateKey) | Sign with Ed25519 |
| signECDSA(message, privateKey, curve) | Sign with ECDSA |
| verifySignature(parsedKey, message, signature) | Verify a signature |
| parsePublicKey(keyString) | Parse SSH public key |
| computeFingerprint(publicKey) | Compute SHA256 fingerprint |
| formatFingerprint(fingerprint) | Format fingerprint for display |
Types
interface FileInfo {
name: string;
type: string;
size: number;
model?: string; // AI model (e.g., "claude-sonnet-4-20250514")
thinking?: string; // Thinking level (e.g., "medium")
}
interface SignatureEnvelope {
sig: string; // Base64-encoded signature
publicKey: string; // SSH format public key
email?: string; // For GitHub identity resolution
githubUser?: string;
}
type KeyType = 'ed25519' | 'ecdsa-p256' | 'ecdsa-p384' | 'ecdsa-p521';Publishing
This package uses NPM Trusted Publishing with OIDC for automated CI/CD deployments. No NPM tokens are required - authentication happens via GitHub Actions OIDC.
Initial setup (one-time, requires npm account with publish access to @coder scope):
Create the package on npm with an initial publish:
cd packages/client npm publish --access publicConfigure trusted publisher on npmjs.com:
- Go to https://www.npmjs.com/package/@coder/mux-md-client/access
- Click "Trusted Publisher" → "GitHub Actions"
- Configure:
- Repository:
coder/mux-md - Workflow:
npm-publish.yml - Environment: (leave blank)
- Repository:
Subsequent publishes happen automatically when
packages/client/**changes are pushed tomain.
License
MIT
