diff --git a/examples/README.md b/examples/README.md index fc55e3b6..9761efe6 100644 --- a/examples/README.md +++ b/examples/README.md @@ -31,6 +31,7 @@ In this directory you can find examples of how to use the `spv-wallet-js-client` 5. `list-transactions` - lists all transactions and with example filtering 6. `send-op-return` - sends an OP_RETURN transaction 7. `admin-remove-user` - removes the user +8. `admin-webhooks` - shows how to set up webhooks and how to handle them In addition to the above, there are additional examples showing how to use the client from a developer perspective: diff --git a/examples/admin-webhooks.ts b/examples/admin-webhooks.ts new file mode 100644 index 00000000..52c03196 --- /dev/null +++ b/examples/admin-webhooks.ts @@ -0,0 +1,27 @@ +import { SpvWalletClient } from '../dist/typescript-npm-package.cjs.js'; +import { exampleAdminKey } from './example-keys.js'; +import { errMessage } from './utils.js'; + +const server = 'http://localhost:3003/v1'; + +if (!exampleAdminKey) { + console.log(errMessage('adminKey')); + process.exit(1); +} + +const adminClient = new SpvWalletClient(server, { + adminKey: exampleAdminKey, +}); + +const webhookSuccessfullySubscribed = await adminClient.AdminSubscribeWebhook( + 'https://example.com', + 'tokenHeader', + 'tokenValue', +); +console.log('Webhook added:', webhookSuccessfullySubscribed); + +const webhooks = await adminClient.AdminGetWebhooks(); +console.log('Webhooks:', webhooks); + +const webhookSuccessfullyUnsubscribed = await adminClient.AdminDeleteWebhook('https://example.com'); +console.log('Webhook deleted:', webhookSuccessfullyUnsubscribed); diff --git a/examples/package.json b/examples/package.json index be1c26da..440189a7 100644 --- a/examples/package.json +++ b/examples/package.json @@ -8,6 +8,7 @@ "_print_starting_label": "echo '' && echo '========== Starting ==========' && echo ''", "run:example": "yarn build:client && yarn _print_starting_label && node --loader ts-node/esm", "admin-add-user": "yarn run:example admin-add-user.ts", + "admin-webhooks": "yarn run:example admin-webhooks.ts", "admin-remove-user": "yarn run:example admin-remove-user.ts", "create-transaction": "yarn run:example create-transaction.ts", "custom-logger": "yarn run:example custom-logger.ts", diff --git a/src/client.ts b/src/client.ts index dba5eb6c..3dba8484 100644 --- a/src/client.ts +++ b/src/client.ts @@ -21,6 +21,7 @@ import { Txs, Utxo, Utxos, + Webhook, XprivWithSigning, XPub, XPubs, @@ -444,6 +445,37 @@ export class SpvWalletClient { return await this.http.adminRequest(`admin/transactions/record`, 'POST', { hex }); } + /** + * Admin only: Subscribe to a webhook with the given URL, token header, and token value. + * + * @param url - The URL to subscribe the webhook to. + * @param tokenHeader - The header name for the authentication token. + * @param tokenValue - The value of the authentication token. + * @returns A Promise that resolves when the webhook subscription is complete. + */ + async AdminSubscribeWebhook(url: string, tokenHeader: string, tokenValue: string): Promise { + return await this.http.adminRequest(`admin/webhooks/subscriptions`, 'POST', { url, tokenHeader, tokenValue }); + } + + /** + * Admin only: Get a list of all webhook subscriptions. + * + * @returns A Promise that resolves to an array of Webhook objects representing the current webhook subscriptions. + */ + async AdminGetWebhooks(): Promise { + return await this.http.adminRequest(`admin/webhooks/subscriptions`, 'GET'); + } + + /** + * Admin only: Delete a webhook subscription by the given URL. + * + * @param url - The URL of the webhook subscription to delete. + * @returns A Promise that resolves when the webhook subscription is deleted. + */ + async AdminDeleteWebhook(url: string): Promise { + return await this.http.adminRequest(`admin/webhooks/subscriptions`, 'DELETE', { url }); + } + /** * Get information about the xpub from the server of the current user * diff --git a/src/index.test.ts b/src/index.test.ts index de38975a..fd2c6736 100644 --- a/src/index.test.ts +++ b/src/index.test.ts @@ -107,31 +107,34 @@ describe('SPVWalletClient admin routing', () => { const adminSPVWalletClient = new SpvWalletClient(testClient.serverURL, options, { level: 'error' }); it.each` - spvWalletMethod | httpMethod | path | act - ${'AdminNewXpub'} | ${'post'} | ${'admin/xpub'} | ${() => adminSPVWalletClient.AdminNewXpub('', {})} - ${'AdminGetStatus'} | ${'get'} | ${'admin/status'} | ${() => adminSPVWalletClient.AdminGetStatus()} - ${'AdminGetStats'} | ${'get'} | ${'admin/stats'} | ${() => adminSPVWalletClient.AdminGetStats()} - ${'AdminGetAccessKeys'} | ${'post'} | ${'admin/access-keys/search'} | ${() => adminSPVWalletClient.AdminGetAccessKeys({}, {}, {})} - ${'AdminGetAccessKeysCount'} | ${'post'} | ${'admin/access-keys/count'} | ${() => adminSPVWalletClient.AdminGetAccessKeysCount({}, {})} - ${'AdminGetContacts'} | ${'post'} | ${'admin/contact/search'} | ${() => adminSPVWalletClient.AdminGetContacts({}, {}, {})} - ${'AdminUpdateContact'} | ${'patch'} | ${'admin/contact/1'} | ${() => adminSPVWalletClient.AdminUpdateContact('1', '', {})} - ${'AdminDeleteContact'} | ${'delete'} | ${'admin/contact/1'} | ${() => adminSPVWalletClient.AdminDeleteContact('1')} - ${'AdminAcceptContact'} | ${'patch'} | ${'admin/contact/accepted/1'} | ${() => adminSPVWalletClient.AdminAcceptContact('1')} - ${'AdminRejectContact'} | ${'patch'} | ${'admin/contact/rejected/1'} | ${() => adminSPVWalletClient.AdminRejectContact('1')} - ${'AdminGetDestinations'} | ${'post'} | ${'admin/destinations/search'} | ${() => adminSPVWalletClient.AdminGetDestinations({}, {}, {})} - ${'AdminGetDestinationsCount'} | ${'post'} | ${'admin/destinations/count'} | ${() => adminSPVWalletClient.AdminGetDestinationsCount({}, {})} - ${'AdminGetPaymail'} | ${'post'} | ${'admin/paymail/get'} | ${() => adminSPVWalletClient.AdminGetPaymail('')} - ${'AdminGetPaymails'} | ${'post'} | ${'admin/paymails/search'} | ${() => adminSPVWalletClient.AdminGetPaymails({}, {}, {})} - ${'AdminGetPaymailsCount'} | ${'post'} | ${'admin/paymails/count'} | ${() => adminSPVWalletClient.AdminGetPaymailsCount({}, {})} - ${'AdminCreatePaymail'} | ${'post'} | ${'admin/paymail/create'} | ${() => adminSPVWalletClient.AdminCreatePaymail('', '', '', '')} - ${'AdminDeletePaymail'} | ${'delete'} | ${'admin/paymail/delete'} | ${() => adminSPVWalletClient.AdminDeletePaymail('')} - ${'AdminGetTransactions'} | ${'post'} | ${'admin/transactions/search'} | ${() => adminSPVWalletClient.AdminGetTransactions({}, {}, {})} - ${'AdminGetTransactionsCount'} | ${'post'} | ${'admin/transactions/count'} | ${() => adminSPVWalletClient.AdminGetTransactionsCount({}, {})} - ${'AdminGetUtxos'} | ${'post'} | ${'admin/utxos/search'} | ${() => adminSPVWalletClient.AdminGetUtxos({}, {}, {})} - ${'AdminGetUtxosCount'} | ${'post'} | ${'admin/utxos/count'} | ${() => adminSPVWalletClient.AdminGetUtxosCount({}, {})} - ${'AdminGetXPubs'} | ${'post'} | ${'admin/xpubs/search'} | ${() => adminSPVWalletClient.AdminGetXPubs({}, {}, {})} - ${'AdminGetXPubsCount'} | ${'post'} | ${'admin/xpubs/count'} | ${() => adminSPVWalletClient.AdminGetXPubsCount({}, {})} - ${'AdminRecordTransaction'} | ${'post'} | ${'admin/transactions/record'} | ${() => adminSPVWalletClient.AdminRecordTransaction('')} + spvWalletMethod | httpMethod | path | act + ${'AdminNewXpub'} | ${'post'} | ${'admin/xpub'} | ${() => adminSPVWalletClient.AdminNewXpub('', {})} + ${'AdminGetStatus'} | ${'get'} | ${'admin/status'} | ${() => adminSPVWalletClient.AdminGetStatus()} + ${'AdminGetStats'} | ${'get'} | ${'admin/stats'} | ${() => adminSPVWalletClient.AdminGetStats()} + ${'AdminGetAccessKeys'} | ${'post'} | ${'admin/access-keys/search'} | ${() => adminSPVWalletClient.AdminGetAccessKeys({}, {}, {})} + ${'AdminGetAccessKeysCount'} | ${'post'} | ${'admin/access-keys/count'} | ${() => adminSPVWalletClient.AdminGetAccessKeysCount({}, {})} + ${'AdminGetContacts'} | ${'post'} | ${'admin/contact/search'} | ${() => adminSPVWalletClient.AdminGetContacts({}, {}, {})} + ${'AdminUpdateContact'} | ${'patch'} | ${'admin/contact/1'} | ${() => adminSPVWalletClient.AdminUpdateContact('1', '', {})} + ${'AdminDeleteContact'} | ${'delete'} | ${'admin/contact/1'} | ${() => adminSPVWalletClient.AdminDeleteContact('1')} + ${'AdminAcceptContact'} | ${'patch'} | ${'admin/contact/accepted/1'} | ${() => adminSPVWalletClient.AdminAcceptContact('1')} + ${'AdminRejectContact'} | ${'patch'} | ${'admin/contact/rejected/1'} | ${() => adminSPVWalletClient.AdminRejectContact('1')} + ${'AdminGetDestinations'} | ${'post'} | ${'admin/destinations/search'} | ${() => adminSPVWalletClient.AdminGetDestinations({}, {}, {})} + ${'AdminGetDestinationsCount'} | ${'post'} | ${'admin/destinations/count'} | ${() => adminSPVWalletClient.AdminGetDestinationsCount({}, {})} + ${'AdminGetPaymail'} | ${'post'} | ${'admin/paymail/get'} | ${() => adminSPVWalletClient.AdminGetPaymail('')} + ${'AdminGetPaymails'} | ${'post'} | ${'admin/paymails/search'} | ${() => adminSPVWalletClient.AdminGetPaymails({}, {}, {})} + ${'AdminGetPaymailsCount'} | ${'post'} | ${'admin/paymails/count'} | ${() => adminSPVWalletClient.AdminGetPaymailsCount({}, {})} + ${'AdminCreatePaymail'} | ${'post'} | ${'admin/paymail/create'} | ${() => adminSPVWalletClient.AdminCreatePaymail('', '', '', '')} + ${'AdminDeletePaymail'} | ${'delete'} | ${'admin/paymail/delete'} | ${() => adminSPVWalletClient.AdminDeletePaymail('')} + ${'AdminGetTransactions'} | ${'post'} | ${'admin/transactions/search'} | ${() => adminSPVWalletClient.AdminGetTransactions({}, {}, {})} + ${'AdminGetTransactionsCount'} | ${'post'} | ${'admin/transactions/count'} | ${() => adminSPVWalletClient.AdminGetTransactionsCount({}, {})} + ${'AdminGetUtxos'} | ${'post'} | ${'admin/utxos/search'} | ${() => adminSPVWalletClient.AdminGetUtxos({}, {}, {})} + ${'AdminGetUtxosCount'} | ${'post'} | ${'admin/utxos/count'} | ${() => adminSPVWalletClient.AdminGetUtxosCount({}, {})} + ${'AdminGetXPubs'} | ${'post'} | ${'admin/xpubs/search'} | ${() => adminSPVWalletClient.AdminGetXPubs({}, {}, {})} + ${'AdminGetXPubsCount'} | ${'post'} | ${'admin/xpubs/count'} | ${() => adminSPVWalletClient.AdminGetXPubsCount({}, {})} + ${'AdminRecordTransaction'} | ${'post'} | ${'admin/transactions/record'} | ${() => adminSPVWalletClient.AdminRecordTransaction('')} + ${'AdminSubscribeWebhook'} | ${'post'} | ${'admin/webhooks/subscriptions'} | ${() => adminSPVWalletClient.AdminSubscribeWebhook('', '', '')} + ${'AdminGetWebhooks'} | ${'get'} | ${'admin/webhooks/subscriptions'} | ${() => adminSPVWalletClient.AdminGetWebhooks()} + ${'AdminDeleteWebhook'} | ${'delete'} | ${'admin/webhooks/subscriptions'} | ${() => adminSPVWalletClient.AdminDeleteWebhook('')} `('$spvWalletMethod', async ({ path, httpMethod, act }) => { // given setupHttpMock(httpMethod, path); diff --git a/src/types.ts b/src/types.ts index 57f9b9eb..68a24877 100644 --- a/src/types.ts +++ b/src/types.ts @@ -642,6 +642,17 @@ export interface AccessKeyWithSigning extends OptionalAdminKey { accessKey: string; } +export interface Webhook { + /** + * The URL for the webhook. + */ + url: string; + /** + * Indicates whether the entity is banned or not. + */ + banned: boolean; +} + export type ClientOptions = XpubWithoutSigning | XprivWithSigning | AccessKeyWithSigning | AdminKey; /**