mirror of
https://github.com/aljazceru/dvmcp.git
synced 2025-12-17 05:14:24 +01:00
feat: implement NIP-09 event deletion for service announcements (v0.1.19)
This commit is contained in:
@@ -8,6 +8,7 @@ A bridge implementation that connects Model Context Protocol (MCP) servers to No
|
||||
- Automatic service announcement using NIP-89
|
||||
- Tool discovery and execution through DVM kind:5910/6910 events
|
||||
- Job status updates and payment handling via kind:7000 events
|
||||
- Service announcement deletion using NIP-09
|
||||
- Comprehensive error handling
|
||||
|
||||
## Configuration
|
||||
@@ -47,6 +48,22 @@ For production:
|
||||
bun run start
|
||||
```
|
||||
|
||||
### Deleting Service Announcements
|
||||
|
||||
To remove your service announcements from relays when shutting down or taking your service offline, you can use the `--delete-announcement` flag:
|
||||
|
||||
```bash
|
||||
bun run start --delete-announcement
|
||||
```
|
||||
|
||||
You can also provide an optional reason for the deletion:
|
||||
|
||||
```bash
|
||||
bun run start --delete-announcement --reason "Service maintenance in progress"
|
||||
```
|
||||
|
||||
This will send a NIP-09 deletion event (kind 5) to all connected relays, instructing them to remove your previously published service announcements.
|
||||
|
||||
## Testing
|
||||
|
||||
Run the test suite:
|
||||
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
import { argv } from 'process';
|
||||
import type { Config } from './src/types';
|
||||
import { setConfigPath } from './src/config.js';
|
||||
import { DVMBridge } from './src/dvm-bridge.js';
|
||||
|
||||
const defaultConfigPath = join(process.cwd(), 'config.dvmcp.yml');
|
||||
let configPath = defaultConfigPath;
|
||||
@@ -118,9 +119,38 @@ const runApp = async () => {
|
||||
await main.default();
|
||||
};
|
||||
|
||||
const deleteAnnouncement = async () => {
|
||||
// Get optional reason from command line arguments
|
||||
const reasonIndex = argv.indexOf('--reason');
|
||||
const reason = reasonIndex !== -1 && argv[reasonIndex + 1] ? argv[reasonIndex + 1] : undefined;
|
||||
|
||||
// Import DVMBridge and perform deletion
|
||||
const bridge = new DVMBridge();
|
||||
|
||||
try {
|
||||
console.log(`${CONFIG_EMOJIS.INFO} Deleting service announcement...`);
|
||||
await bridge.deleteAnnouncement(reason);
|
||||
console.log(`${CONFIG_EMOJIS.SUCCESS} Service announcement deleted successfully`);
|
||||
process.exit(0);
|
||||
} catch (error) {
|
||||
console.error(`${CONFIG_EMOJIS.INFO} Failed to delete service announcement:`, error);
|
||||
process.exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
const cliMain = async () => {
|
||||
if (argv.includes('--configure')) {
|
||||
await configure();
|
||||
return;
|
||||
}
|
||||
|
||||
if (argv.includes('--delete-announcement')) {
|
||||
if (!existsSync(configPath)) {
|
||||
console.error(`${CONFIG_EMOJIS.INFO} No configuration file found at ${configPath}`);
|
||||
process.exit(1);
|
||||
}
|
||||
await deleteAnnouncement();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!existsSync(configPath)) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@dvmcp/bridge",
|
||||
"version": "0.1.18",
|
||||
"version": "0.1.19",
|
||||
"description": "Bridge connecting MCP servers to Nostr's DVM ecosystem",
|
||||
"module": "index.ts",
|
||||
"type": "module",
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
DVM_ANNOUNCEMENT_KIND,
|
||||
TOOL_REQUEST_KIND,
|
||||
} from '@dvmcp/commons/constants';
|
||||
import type { Event } from 'nostr-tools/pure';
|
||||
|
||||
export const keyManager = createKeyManager(CONFIG.nostr.privateKey);
|
||||
|
||||
@@ -57,4 +58,37 @@ export class NostrAnnouncer {
|
||||
async updateAnnouncement() {
|
||||
await Promise.all([this.announceService(), this.announceRelayList()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the service announcement from relays using NIP-09
|
||||
* @param reason Optional reason for deletion
|
||||
* @returns The deletion event that was published
|
||||
*/
|
||||
async deleteAnnouncement(reason: string = 'Service offline'): Promise<Event> {
|
||||
// First, query the relays to find our announcement event
|
||||
const announcementFilter = {
|
||||
kinds: [DVM_ANNOUNCEMENT_KIND],
|
||||
authors: [keyManager.getPublicKey()],
|
||||
};
|
||||
|
||||
const events = await this.relayHandler.queryEvents(announcementFilter);
|
||||
|
||||
// Create the deletion event (NIP-09)
|
||||
const deletionEvent = keyManager.signEvent({
|
||||
...keyManager.createEventTemplate(5), // kind 5 is for deletion requests
|
||||
content: reason,
|
||||
tags: [
|
||||
// Add tags for each event to be deleted
|
||||
...events.map(event => ['e', event.id]),
|
||||
// Add the kind of events being deleted
|
||||
['k', `${DVM_ANNOUNCEMENT_KIND}`],
|
||||
],
|
||||
});
|
||||
|
||||
// Publish the deletion event
|
||||
await this.relayHandler.publishEvent(deletionEvent);
|
||||
console.log(`Published deletion event for service announcement`);
|
||||
|
||||
return deletionEvent;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,6 +83,23 @@ export class DVMBridge {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the service announcement from relays
|
||||
* @param reason Optional reason for deletion
|
||||
* @returns The deletion event that was published
|
||||
*/
|
||||
async deleteAnnouncement(reason?: string) {
|
||||
console.log('Deleting service announcement from relays...');
|
||||
try {
|
||||
const deletionEvent = await this.nostrAnnouncer.deleteAnnouncement(reason);
|
||||
console.log('Service announcement deleted successfully');
|
||||
return deletionEvent;
|
||||
} catch (error) {
|
||||
console.error('Error deleting service announcement:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
private async handleRequest(event: Event) {
|
||||
try {
|
||||
if (this.isWhitelisted(event.pubkey)) {
|
||||
|
||||
Reference in New Issue
Block a user