nostr-signer-capacitor-plugin
v0.0.5
Published
This capacitor plugin uses the intents package to interact with nostr signer apps on the Android platform
Maintainers
Readme
Nostr Signer Capacitor Plugin
This Capacitor plugin allows your application to interact with Nostr signer apps on the Android platform using intents, following the NIP-55 specification.
Install
npm install nostr-signer-capacitor-plugin
npx cap syncRequirements
- Android: minSdkVersion 23 or higher.
- Java 21 (JDK 21) for building Android with Gradle.
- Capacitor 7.x.
Version
Current version: 0.0.5
0.0.5 (2025-09-22)
- Bumped Android
minSdkVersionto 23 to align with Capacitor Android requirements. - Added Android unit tests (Robolectric) covering Content Resolver flows and rejected-provider fallback.
- Added npm scripts:
test:ts– runs TypeScript/Jest teststest:android– runs Android unit tests (testDebugUnitTest)test:all(defaultnpm test) – runs both suites
- Added GitHub Actions workflow at
.github/workflows/ci.ymlto run JS and Android unit tests in CI.
Testing
Run TypeScript tests:
npm run test:tsRun Android unit tests:
cd android
./gradlew clean testDebugUnitTest --no-daemon --stacktrace --info --console=plainRun all tests:
npm testUsage
Import the Plugin
import NostrSignerPlugin from 'nostr-signer-capacitor-plugin';Set the Signer Package Name
Before using the plugin on Android, you need to set the package name of the external signer app.
await NostrSignerPlugin.setPackageName({ packageName: 'com.example.signer' });Check if External Signer is Installed
const { installed } = await NostrSignerPlugin.isExternalSignerInstalled();
if (!installed) {
console.log('External signer app is not installed.');
}Get a List of Installed External Signers
try {
const result = await NostrSignerPlugin.getInstalledSignerApps();
signerApps = result.apps;
console.log('Installed Signer Apps:', signerApps);
} catch (error) {
console.error('Error getting installed signer apps:', error);
}The AppInfo object has the following fields"
export interface AppInfo {
name: string; // The name of the app as it appears in the System launcher
packageName: string; // The package name of the app - pass this to setPackageName
iconData: string; // the base 64 encoded string of the app's icon
iconUrl: string; // the url to app's icon
}
Get Public Key
try {
const { npub } = await NostrSignerPlugin.getPublicKey();
console.log('Public Key:', npub);
} catch (error) {
console.error('Error getting public key:', error);
}Sign Event
const event = {
kind: 1,
content: 'Hello, Nostr!',
tags: [],
created_at: Math.floor(Date.now() / 1000),
};
try {
const { event: signedEventJson } = await NostrSignerPlugin.signEvent({
eventJson: JSON.stringify(event),
});
const signedEvent = JSON.parse(signedEventJson);
console.log('Signed Event:', signedEvent);
} catch (error) {
console.error('Error signing event:', error);
}NIP-04 Encrypt
try {
const { result: encryptedText } = await NostrSignerPlugin.nip04Encrypt({
pubKey: 'recipient_public_key',
plainText: 'Secret message',
});
console.log('Encrypted Text:', encryptedText);
} catch (error) {
console.error('Error encrypting message:', error);
}NIP-04 Decrypt
try {
const { result: decryptedText } = await NostrSignerPlugin.nip04Decrypt({
pubKey: 'sender_public_key',
encryptedText: 'encrypted_text',
});
console.log('Decrypted Text:', decryptedText);
} catch (error) {
console.error('Error decrypting message:', error);
}NIP-44 Encrypt
try {
const { result: encryptedText } = await NostrSignerPlugin.nip44Encrypt({
pubKey: 'recipient_public_key',
plainText: 'Secret message',
});
console.log('Encrypted Text (NIP-44):', encryptedText);
} catch (error) {
console.error('Error encrypting message (NIP-44):', error);
}NIP-44 Decrypt
try {
const { result: decryptedText } = await NostrSignerPlugin.nip44Decrypt({
pubKey: 'sender_public_key',
encryptedText: 'encrypted_text',
});
console.log('Decrypted Text (NIP-44):', decryptedText);
} catch (error) {
console.error('Error decrypting message (NIP-44):', error);
}Decrypt Zap Event
try {
const { result: decryptedEventJson } = await NostrSignerPlugin.decryptZapEvent({
eventJson: JSON.stringify(encryptedEvent),
});
const decryptedEvent = JSON.parse(decryptedEventJson);
console.log('Decrypted Zap Event:', decryptedEvent);
} catch (error) {
console.error('Error decrypting zap event:', error);
}API
getInstalledSignerApps(...)setPackageName(...)isExternalSignerInstalled()getPublicKey()signEvent(...)nip04Encrypt(...)nip04Decrypt(...)nip44Encrypt(...)nip44Decrypt(...)decryptZapEvent(...)
getInstalledSignerApps(...)
getInstalledSignerApps() => Promise<{ apps: AppInfo[] }>Returns a list of AppInfo objects which contain information about which Signer apps are installed.
Returns: Promise<{ apps: AppInfop[] }>
setPackageName(...)
setPackageName(options: { packageName: string; }) => Promise<void>Sets the package name of the external Nostr signer app. This is required on Android to specify which app to interact with.
| Param | Type | Description |
| ------------- | ------------------------------------ | --------------------------------------------- |
| options | { packageName: string; } | An object containing the package name string. |
isExternalSignerInstalled()
isExternalSignerInstalled() => Promise<{ installed: boolean; }>Checks if the external Nostr signer app is installed on the device.
Returns: Promise<{ installed: boolean; }>
An object indicating whether the signer app is installed.
getPublicKey()
getPublicKey() => Promise<{ npub: string; }>Requests the public key from the Nostr signer app or extension.
Returns: Promise<{ npub: string; }>
An object containing the public key in npub format.
signEvent(...)
signEvent(options: { eventJson: string; }) => Promise<{ event: string; }>Requests the signer app to sign a Nostr event.
| Param | Type | Description |
| ------------- | ----------------------------------- | --------------------------------- |
| options | { eventJson: string; } | An object containing the event in JSON string format. |
Returns: Promise<{ event: string; }>
An object containing the signed event in JSON string format.
nip04Encrypt(...)
nip04Encrypt(options: { plainText: string; pubKey: string; }) => Promise<{ result: string; }>Encrypts a message using NIP-04 encryption.
| Param | Type | Description |
| ------------- | ----------------------------------------------------- | ------------------------------------------- |
| options | { plainText: string; pubKey: string; } | An object containing the plaintext and the recipient's public key. |
Returns: Promise<{ result: string; }>
An object containing the encrypted text.
nip04Decrypt(...)
nip04Decrypt(options: { encryptedText: string; pubKey: string; }) => Promise<{ result: string; }>Decrypts a message using NIP-04 decryption.
| Param | Type | Description |
| ------------- | ------------------------------------------------------- | ------------------------------------------- |
| options | { encryptedText: string; pubKey: string; } | An object containing the encrypted text and the sender's public key. |
Returns: Promise<{ result: string; }>
An object containing the decrypted plaintext.
nip44Encrypt(...)
nip44Encrypt(options: { plainText: string; pubKey: string; }) => Promise<{ result: string; }>Encrypts a message using NIP-44 encryption.
| Param | Type | Description |
| ------------- | ----------------------------------------------------- | ------------------------------------------- |
| options | { plainText: string; pubKey: string; } | An object containing the plaintext and the recipient's public key. |
Returns: Promise<{ result: string; }>
An object containing the encrypted text.
nip44Decrypt(...)
nip44Decrypt(options: { encryptedText: string; pubKey: string; }) => Promise<{ result: string; }>Decrypts a message using NIP-44 decryption.
| Param | Type | Description |
| ------------- | ------------------------------------------------------- | ------------------------------------------- |
| options | { encryptedText: string; pubKey: string; } | An object containing the encrypted text and the sender's public key. |
Returns: Promise<{ result: string; }>
An object containing the decrypted plaintext.
decryptZapEvent(...)
decryptZapEvent(options: { eventJson: string; }) => Promise<{ result: string; }>Decrypts a zap event.
| Param | Type | Description |
| ------------- | ----------------------------------- | --------------------------------- |
| options | { eventJson: string; } | An object containing the encrypted zap event in JSON string format. |
Returns: Promise<{ result: string; }>
An object containing the decrypted zap event in JSON string format.
Notes
- On Android, the plugin communicates with external signer apps using intents and the Content Resolver as per NIP-55.
- Ensure that the external signer app or browser extension supports the required NIP specifications.
