@notabene/javascript-sdk 2.19.0 → 2.20.0-next.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,6 +4,7 @@ import type { DID, RefreshSource } from '../../types';
4
4
  import {
5
5
  ConnectionManager,
6
6
  type ConnectionStatus,
7
+ decryptCounterpartyAssistPayload,
7
8
  getRefreshResult,
8
9
  type TransactionType,
9
10
  } from '../connections';
@@ -53,6 +54,7 @@ const arbConnectionMetadata = fc.record({
53
54
  participants: fc.array(fc.string(), { minLength: 1 }), // At least one participant
54
55
  nodeUrl: fc.webUrl(),
55
56
  transactionType: fc.constantFrom<TransactionType>('withdraw', 'deposit'),
57
+ webhookUrl: fc.option(fc.webUrl(), { nil: undefined }),
56
58
  });
57
59
 
58
60
  describe('ConnectionManager', () => {
@@ -317,6 +319,7 @@ describe('ConnectionManager', () => {
317
319
  const refreshSource: RefreshSource = {
318
320
  url: 'https://test-endpoint.com',
319
321
  key: sealed.key,
322
+ id: 'test-id',
320
323
  };
321
324
 
322
325
  // Common metadata for all tests
@@ -385,6 +388,7 @@ describe('ConnectionManager', () => {
385
388
  const completedRefreshSource: RefreshSource = {
386
389
  url: 'https://test-endpoint.com',
387
390
  key: completedSealed.key,
391
+ id: 'test-id',
388
392
  };
389
393
 
390
394
  const mockResponse = createMockResponse(
@@ -435,3 +439,28 @@ describe('ConnectionManager', () => {
435
439
  });
436
440
  });
437
441
  });
442
+
443
+ describe('decryptCounterpartyAssistPayload', () => {
444
+ it('round-trips a sealed payload back to the original object', async () => {
445
+ const original = { result: { ref: 'abc' }, tx: { amount: '10' } };
446
+ const sealed = await seal(original);
447
+
448
+ const decrypted = await decryptCounterpartyAssistPayload<typeof original>({
449
+ sealed: sealed.ciphertext,
450
+ key: sealed.key,
451
+ });
452
+
453
+ expect(decrypted).toEqual(original);
454
+ });
455
+
456
+ it('throws when the key is wrong', async () => {
457
+ const sealed = await seal({ a: 1 });
458
+ const other = await seal({ b: 2 });
459
+ await expect(
460
+ decryptCounterpartyAssistPayload({
461
+ sealed: sealed.ciphertext,
462
+ key: other.key,
463
+ }),
464
+ ).rejects.toThrow();
465
+ });
466
+ });
@@ -24,6 +24,14 @@ export interface ConnectionMetadata {
24
24
  readonly participants: readonly string[];
25
25
  readonly transactionType: TransactionType;
26
26
  readonly locale?: string;
27
+ /**
28
+ * Delivery target for Counterparty Assist completion/closure webhooks.
29
+ * Sent and stored as plaintext so the connection can route the event, so do not
30
+ * embed secrets (e.g. `?token=`) in this URL. Webhook payloads carry the encrypted
31
+ * `sealed` blob, whose successful decryption is itself an authenticity check;
32
+ * signed delivery is provided by the future Svix-backed pipeline.
33
+ */
34
+ readonly webhookUrl?: string;
27
35
  }
28
36
 
29
37
  export interface ConnectionResponse<T extends ComponentRequest> {
@@ -61,7 +69,7 @@ export type ConnectionResult<T extends ComponentRequest> =
61
69
  * @returns Promise resolving to connection result with decrypted data
62
70
  */
63
71
  export async function getRefreshResult<T extends ComponentRequest>(
64
- refreshSource: RefreshSource,
72
+ refreshSource: Pick<RefreshSource, 'url' | 'key'>,
65
73
  ): Promise<ConnectionResult<T>> {
66
74
  const response = await fetch(refreshSource.url, {
67
75
  method: 'GET',
@@ -109,6 +117,22 @@ export async function getRefreshResult<T extends ComponentRequest>(
109
117
  };
110
118
  }
111
119
 
120
+ /**
121
+ * Decrypt a Counterparty Assist webhook payload with the key the VASP captured
122
+ * at connection creation. Single call, no network fetch (the webhook already
123
+ * carried the ciphertext).
124
+ * @public
125
+ */
126
+ export async function decryptCounterpartyAssistPayload<T>({
127
+ sealed,
128
+ key,
129
+ }: {
130
+ sealed: string;
131
+ key: string;
132
+ }): Promise<T> {
133
+ return unseal<T>({ ciphertext: sealed, key });
134
+ }
135
+
112
136
  /**
113
137
  * Manages encrypted connections using Cloudflare Durable Objects
114
138
  */