@notabene/javascript-sdk 2.16.0-next.1 → 2.16.0-next.4
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.
- package/dist/cjs/notabene.cjs +5 -5
- package/dist/cjs/notabene.d.ts +861 -4
- package/dist/cjs/package.json +1 -1
- package/dist/esm/notabene.d.ts +861 -4
- package/dist/esm/notabene.js +849 -811
- package/dist/esm/package.json +1 -1
- package/dist/notabene.d.ts +861 -4
- package/dist/notabene.js +849 -811
- package/package.json +1 -1
- package/src/__tests__/notabene.test.ts +24 -0
- package/src/ivms/v2Types.ts +1 -2
- package/src/notabene.ts +20 -0
- package/src/responseTransformer/__tests__/transformer.test.ts +84 -7
- package/src/responseTransformer/__tests__/utils.test.ts +21 -1
- package/src/responseTransformer/mappers.ts +19 -29
- package/src/responseTransformer/transformer.ts +77 -9
- package/src/responseTransformer/types.ts +4 -4
- package/src/responseTransformer/utils.ts +10 -15
- package/src/types.ts +12 -0
package/package.json
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"author": "Notabene <developers@notabene.id>",
|
|
11
11
|
"license": "MIT",
|
|
12
12
|
"packageManager": "yarn@4.5.1",
|
|
13
|
-
"version": "2.16.0-next.
|
|
13
|
+
"version": "2.16.0-next.4",
|
|
14
14
|
"source": "src/notabene.ts",
|
|
15
15
|
"main": "dist/cjs/notabene.cjs",
|
|
16
16
|
"module": "dist/esm/notabene.js",
|
|
@@ -340,6 +340,30 @@ describe('Notabene', () => {
|
|
|
340
340
|
});
|
|
341
341
|
});
|
|
342
342
|
|
|
343
|
+
describe('createInvoiceReader', () => {
|
|
344
|
+
test.prop([
|
|
345
|
+
fc.string({ minLength: 3 }), // authToken
|
|
346
|
+
arbitraryNodeUrl(), // nodeUrl
|
|
347
|
+
])(
|
|
348
|
+
'Should create invoice reader component with correct URL',
|
|
349
|
+
(authToken, nodeUrl) => {
|
|
350
|
+
const notabene = new Notabene({
|
|
351
|
+
nodeUrl,
|
|
352
|
+
authToken,
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
const component = notabene.createInvoiceReader();
|
|
356
|
+
const url = new URL(component.url);
|
|
357
|
+
|
|
358
|
+
return (
|
|
359
|
+
url.pathname === '/flow-link/invoice-reader' &&
|
|
360
|
+
url.hash ===
|
|
361
|
+
`#authToken=${encodeURIComponent(authToken)}&value=${encodeURIComponent(JSON.stringify({}))}` &&
|
|
362
|
+
url.searchParams.get('nodeUrl') === nodeUrl
|
|
363
|
+
);
|
|
364
|
+
},
|
|
365
|
+
);
|
|
366
|
+
});
|
|
343
367
|
describe('uxUrl trailing slash normalization', () => {
|
|
344
368
|
it('should strip a single trailing slash', () => {
|
|
345
369
|
const notabene = new Notabene({
|
package/src/ivms/v2Types.ts
CHANGED
|
@@ -7,12 +7,10 @@ import type {
|
|
|
7
7
|
|
|
8
8
|
export type OriginatorV2 = {
|
|
9
9
|
originatorPerson: PersonV2[];
|
|
10
|
-
customerIdentification?: string;
|
|
11
10
|
};
|
|
12
11
|
|
|
13
12
|
export type BeneficiaryV2 = {
|
|
14
13
|
beneficiaryPerson: PersonV2[];
|
|
15
|
-
customerIdentification?: string;
|
|
16
14
|
};
|
|
17
15
|
|
|
18
16
|
export type NaturalPersonNameIDV2 = {
|
|
@@ -27,6 +25,7 @@ export type NaturalPersonNameV2 = Omit<NaturalPersonName, 'nameIdentifier'> & {
|
|
|
27
25
|
|
|
28
26
|
export type NaturalPersonV2 = Omit<NaturalPerson, 'name'> & {
|
|
29
27
|
name: NaturalPersonNameV2;
|
|
28
|
+
customerIdentification?: string;
|
|
30
29
|
};
|
|
31
30
|
|
|
32
31
|
export type PersonV2 = Omit<Person, 'naturalPerson'> & {
|
package/src/notabene.ts
CHANGED
|
@@ -30,6 +30,7 @@ import type {
|
|
|
30
30
|
FieldTypes,
|
|
31
31
|
HostMessage,
|
|
32
32
|
InvalidValue,
|
|
33
|
+
InvoiceReaderResponse,
|
|
33
34
|
IVMS101,
|
|
34
35
|
LegalPerson,
|
|
35
36
|
LegalPersonFieldName,
|
|
@@ -96,6 +97,7 @@ export type {
|
|
|
96
97
|
TransactionCreateRequestV2,
|
|
97
98
|
TransactionIVMS101Request,
|
|
98
99
|
} from './responseTransformer';
|
|
100
|
+
export type { Invoice } from './types';
|
|
99
101
|
export {
|
|
100
102
|
ConnectionManager,
|
|
101
103
|
getRefreshResult,
|
|
@@ -153,6 +155,7 @@ export type {
|
|
|
153
155
|
FieldTypes,
|
|
154
156
|
HostMessage,
|
|
155
157
|
InvalidValue,
|
|
158
|
+
InvoiceReaderResponse,
|
|
156
159
|
IVMS101,
|
|
157
160
|
LegalPerson,
|
|
158
161
|
LegalPersonFieldName,
|
|
@@ -403,6 +406,23 @@ export default class Notabene {
|
|
|
403
406
|
);
|
|
404
407
|
}
|
|
405
408
|
|
|
409
|
+
/**
|
|
410
|
+
* Creates an invoice reader component for extracting TAIP-16 invoice data from PDF invoices
|
|
411
|
+
*
|
|
412
|
+
* The component provides a PDF drag-and-drop upload UI. On upload, the PDF is
|
|
413
|
+
* parsed and the extracted invoice data is returned. On completion,
|
|
414
|
+
* the response contains the TAIP-16 invoice data.
|
|
415
|
+
*
|
|
416
|
+
* @returns A new EmbeddedComponent instance for invoice reader creation
|
|
417
|
+
* @public
|
|
418
|
+
*/
|
|
419
|
+
public createInvoiceReader() {
|
|
420
|
+
return this.createComponent<InvoiceReaderResponse, Record<string, never>>(
|
|
421
|
+
'flow-link/invoice-reader',
|
|
422
|
+
{},
|
|
423
|
+
);
|
|
424
|
+
}
|
|
425
|
+
|
|
406
426
|
/**
|
|
407
427
|
* Creates a deposit assist component
|
|
408
428
|
*
|
|
@@ -2,7 +2,11 @@ import { describe, expect, it } from 'vitest';
|
|
|
2
2
|
import type { OriginatorV2 } from '../../ivms/v2Types';
|
|
3
3
|
import type { Deposit, TransactionResponse, Withdrawal } from '../../types';
|
|
4
4
|
import { PersonType } from '../../types';
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
componentResponseToTxRequests,
|
|
7
|
+
enrichConfig,
|
|
8
|
+
uuid,
|
|
9
|
+
} from '../transformer';
|
|
6
10
|
|
|
7
11
|
// Common test constants
|
|
8
12
|
const TEST_DELEGATE_TOKEN = 'test-delegate-token';
|
|
@@ -506,6 +510,35 @@ describe('componentResponseToTxRequests', () => {
|
|
|
506
510
|
});
|
|
507
511
|
});
|
|
508
512
|
|
|
513
|
+
const UUID_REGEX =
|
|
514
|
+
/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
|
|
515
|
+
|
|
516
|
+
describe('uuid', () => {
|
|
517
|
+
it('should return a valid UUID v4 format', () => {
|
|
518
|
+
const result = uuid();
|
|
519
|
+
expect(result).toMatch(UUID_REGEX);
|
|
520
|
+
});
|
|
521
|
+
|
|
522
|
+
it('should return unique values on each call', () => {
|
|
523
|
+
const results = new Set(Array.from({ length: 100 }, () => uuid()));
|
|
524
|
+
expect(results.size).toBe(100);
|
|
525
|
+
});
|
|
526
|
+
|
|
527
|
+
it('should always have version 4 indicator', () => {
|
|
528
|
+
for (let i = 0; i < 50; i++) {
|
|
529
|
+
const result = uuid();
|
|
530
|
+
expect(result[14]).toBe('4');
|
|
531
|
+
}
|
|
532
|
+
});
|
|
533
|
+
|
|
534
|
+
it('should always have a valid variant nibble (8, 9, a, or b)', () => {
|
|
535
|
+
for (let i = 0; i < 50; i++) {
|
|
536
|
+
const result = uuid();
|
|
537
|
+
expect('89ab').toContain(result[19]);
|
|
538
|
+
}
|
|
539
|
+
});
|
|
540
|
+
});
|
|
541
|
+
|
|
509
542
|
describe('enrichConfig', () => {
|
|
510
543
|
const CUSTOMER_DID = 'did:key:customer123';
|
|
511
544
|
const SOURCE_ADDRESS = '0xsource123';
|
|
@@ -520,7 +553,7 @@ describe('enrichConfig', () => {
|
|
|
520
553
|
}
|
|
521
554
|
|
|
522
555
|
describe('withdrawal transactions', () => {
|
|
523
|
-
it('should extract originatorId from delegate token and
|
|
556
|
+
it('should extract originatorId from delegate token and fall back to urn:uuid for beneficiaryId', () => {
|
|
524
557
|
const delegateToken = createDelegateToken(CUSTOMER_DID);
|
|
525
558
|
const withdrawal = {
|
|
526
559
|
destination: DESTINATION_ADDRESS,
|
|
@@ -531,7 +564,7 @@ describe('enrichConfig', () => {
|
|
|
531
564
|
const result = enrichConfig({}, delegateToken, withdrawal);
|
|
532
565
|
|
|
533
566
|
expect(result.originatorId).toBe(CUSTOMER_DID);
|
|
534
|
-
expect(result.beneficiaryId).
|
|
567
|
+
expect(result.beneficiaryId).toMatch(/^urn:uuid:[0-9a-f-]{36}$/);
|
|
535
568
|
});
|
|
536
569
|
|
|
537
570
|
it('should set beneficiaryId equal to originatorId for self-transfers', () => {
|
|
@@ -572,7 +605,7 @@ describe('enrichConfig', () => {
|
|
|
572
605
|
});
|
|
573
606
|
|
|
574
607
|
describe('deposit transactions', () => {
|
|
575
|
-
it('should extract beneficiaryId from delegate token and
|
|
608
|
+
it('should extract beneficiaryId from delegate token and fall back to urn:uuid for originatorId', () => {
|
|
576
609
|
const delegateToken = createDelegateToken(CUSTOMER_DID);
|
|
577
610
|
const deposit = {
|
|
578
611
|
source: SOURCE_ADDRESS,
|
|
@@ -583,7 +616,7 @@ describe('enrichConfig', () => {
|
|
|
583
616
|
const result = enrichConfig({}, delegateToken, deposit);
|
|
584
617
|
|
|
585
618
|
expect(result.beneficiaryId).toBe(CUSTOMER_DID);
|
|
586
|
-
expect(result.originatorId).
|
|
619
|
+
expect(result.originatorId).toMatch(/^urn:uuid:[0-9a-f-]{36}$/);
|
|
587
620
|
});
|
|
588
621
|
|
|
589
622
|
it('should set originatorId equal to beneficiaryId for self-transfers', () => {
|
|
@@ -632,7 +665,51 @@ describe('enrichConfig', () => {
|
|
|
632
665
|
|
|
633
666
|
const result = enrichConfig({}, 'invalid-token', withdrawal);
|
|
634
667
|
|
|
635
|
-
expect(result.originatorId).
|
|
636
|
-
expect(result.beneficiaryId).
|
|
668
|
+
expect(result.originatorId).toMatch(/^urn:uuid:[0-9a-f-]{36}$/);
|
|
669
|
+
expect(result.beneficiaryId).toMatch(/^urn:uuid:[0-9a-f-]{36}$/);
|
|
670
|
+
});
|
|
671
|
+
|
|
672
|
+
describe('UUID fallback', () => {
|
|
673
|
+
it('should generate a valid urn:uuid for missing beneficiaryId', () => {
|
|
674
|
+
const delegateToken = createDelegateToken(CUSTOMER_DID);
|
|
675
|
+
const withdrawal = {
|
|
676
|
+
destination: DESTINATION_ADDRESS,
|
|
677
|
+
asset: TEST_ASSET,
|
|
678
|
+
amountDecimal: 100,
|
|
679
|
+
} as Withdrawal;
|
|
680
|
+
|
|
681
|
+
const result = enrichConfig({}, delegateToken, withdrawal);
|
|
682
|
+
|
|
683
|
+
expect(result.originatorId).toBe(CUSTOMER_DID);
|
|
684
|
+
expect(result.beneficiaryId).toMatch(/^urn:uuid:[0-9a-f-]{36}$/);
|
|
685
|
+
});
|
|
686
|
+
|
|
687
|
+
it('should generate a valid urn:uuid for missing originatorId', () => {
|
|
688
|
+
const delegateToken = createDelegateToken(CUSTOMER_DID);
|
|
689
|
+
const deposit = {
|
|
690
|
+
source: SOURCE_ADDRESS,
|
|
691
|
+
asset: TEST_ASSET,
|
|
692
|
+
amountDecimal: 100,
|
|
693
|
+
} as Deposit;
|
|
694
|
+
|
|
695
|
+
const result = enrichConfig({}, delegateToken, deposit);
|
|
696
|
+
|
|
697
|
+
expect(result.beneficiaryId).toBe(CUSTOMER_DID);
|
|
698
|
+
expect(result.originatorId).toMatch(/^urn:uuid:[0-9a-f-]{36}$/);
|
|
699
|
+
});
|
|
700
|
+
|
|
701
|
+
it('should generate unique UUIDs for each call', () => {
|
|
702
|
+
const withdrawal = {
|
|
703
|
+
destination: DESTINATION_ADDRESS,
|
|
704
|
+
asset: TEST_ASSET,
|
|
705
|
+
amountDecimal: 100,
|
|
706
|
+
} as Withdrawal;
|
|
707
|
+
|
|
708
|
+
const result1 = enrichConfig({}, 'invalid-token', withdrawal);
|
|
709
|
+
const result2 = enrichConfig({}, 'invalid-token', withdrawal);
|
|
710
|
+
|
|
711
|
+
expect(result1.beneficiaryId).not.toBe(result2.beneficiaryId);
|
|
712
|
+
expect(result1.originatorId).not.toBe(result2.originatorId);
|
|
713
|
+
});
|
|
637
714
|
});
|
|
638
715
|
});
|
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
import { describe, expect, it } from 'vitest';
|
|
2
|
-
import { getCaip10ChainPrefix } from '../utils';
|
|
2
|
+
import { getCaip10ChainPrefix, getPartyId } from '../utils';
|
|
3
|
+
|
|
4
|
+
describe('getPartyId', () => {
|
|
5
|
+
it('should return mailto: IRI when party has email', () => {
|
|
6
|
+
expect(getPartyId({ email: 'test@example.com' })).toBe(
|
|
7
|
+
'mailto:test@example.com',
|
|
8
|
+
);
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it('should return undefined when party has no email', () => {
|
|
12
|
+
expect(getPartyId({})).toBeUndefined();
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it('should return undefined when party is undefined', () => {
|
|
16
|
+
expect(getPartyId(undefined)).toBeUndefined();
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('should return undefined when called with no arguments', () => {
|
|
20
|
+
expect(getPartyId()).toBeUndefined();
|
|
21
|
+
});
|
|
22
|
+
});
|
|
3
23
|
|
|
4
24
|
describe('getCaip10ChainPrefix', () => {
|
|
5
25
|
it('should extract chain prefix from EIP155 CAIP-10 address', () => {
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
+
import type { Agent, DID } from '@taprsvp/types';
|
|
1
2
|
import type {
|
|
2
3
|
Beneficiary,
|
|
3
4
|
NaturalPerson,
|
|
4
5
|
NaturalPersonName,
|
|
5
6
|
Originator,
|
|
6
7
|
Person,
|
|
7
|
-
} from '
|
|
8
|
-
import type { Agent } from '@taprsvp/types';
|
|
8
|
+
} from '../ivms';
|
|
9
9
|
import {
|
|
10
10
|
PersonType,
|
|
11
11
|
type Deposit,
|
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
type Withdrawal,
|
|
15
15
|
} from '../types';
|
|
16
16
|
import type {
|
|
17
|
+
BaseRequestConfig,
|
|
17
18
|
ResponseToIVMS101RequestConfig,
|
|
18
19
|
ResponseToTxCreateRequestConfig,
|
|
19
20
|
TransactionCreateRequest,
|
|
@@ -23,7 +24,6 @@ import type {
|
|
|
23
24
|
import {
|
|
24
25
|
convertPersonToV2,
|
|
25
26
|
getCaip10ChainPrefix,
|
|
26
|
-
getPartyId,
|
|
27
27
|
isDeposit,
|
|
28
28
|
isWithdrawal,
|
|
29
29
|
} from './utils';
|
|
@@ -237,22 +237,10 @@ export function mapToV1CreateRequest(
|
|
|
237
237
|
export function mapToTransactCreateRequest(
|
|
238
238
|
transaction: Withdrawal | Deposit,
|
|
239
239
|
payload: V1Transaction,
|
|
240
|
-
config: ResponseToTxCreateRequestConfig
|
|
240
|
+
config: ResponseToTxCreateRequestConfig & Required<BaseRequestConfig>,
|
|
241
241
|
): TransactionCreateRequestV2 {
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
const isWithdrawalTx = isWithdrawal(transaction);
|
|
245
|
-
const originatorParty = isWithdrawalTx
|
|
246
|
-
? transaction.customer
|
|
247
|
-
: transaction.counterparty;
|
|
248
|
-
const beneficiaryParty = isWithdrawalTx
|
|
249
|
-
? transaction.counterparty
|
|
250
|
-
: transaction.customer;
|
|
251
|
-
|
|
252
|
-
const originatorId =
|
|
253
|
-
config?.originatorId || getPartyId('originator', originatorParty);
|
|
254
|
-
const beneficiaryId =
|
|
255
|
-
config?.beneficiaryId || getPartyId('beneficiary', beneficiaryParty);
|
|
242
|
+
const originatorId = config.originatorId;
|
|
243
|
+
const beneficiaryId = config.beneficiaryId;
|
|
256
244
|
const referenceId =
|
|
257
245
|
config?.referenceId ||
|
|
258
246
|
payload.transactionId ||
|
|
@@ -262,7 +250,8 @@ export function mapToTransactCreateRequest(
|
|
|
262
250
|
if (payload.originatorVASPdid) {
|
|
263
251
|
agents.push({
|
|
264
252
|
'@id': payload.originatorVASPdid,
|
|
265
|
-
|
|
253
|
+
// tap type needs to be updated to accept IRI as valid id
|
|
254
|
+
for: originatorId as DID,
|
|
266
255
|
role: 'VASP',
|
|
267
256
|
});
|
|
268
257
|
}
|
|
@@ -270,7 +259,8 @@ export function mapToTransactCreateRequest(
|
|
|
270
259
|
if (payload.beneficiaryVASPdid) {
|
|
271
260
|
agents.push({
|
|
272
261
|
'@id': payload.beneficiaryVASPdid,
|
|
273
|
-
|
|
262
|
+
// tap type needs to be updated to accept IRI as valid id
|
|
263
|
+
for: beneficiaryId as DID,
|
|
274
264
|
role: 'VASP',
|
|
275
265
|
});
|
|
276
266
|
}
|
|
@@ -278,7 +268,8 @@ export function mapToTransactCreateRequest(
|
|
|
278
268
|
if (isWithdrawal(transaction) && transaction?.account?.did) {
|
|
279
269
|
agents.push({
|
|
280
270
|
'@id': transaction.account.did,
|
|
281
|
-
|
|
271
|
+
// tap type needs to be updated to accept IRI as valid id
|
|
272
|
+
for: (payload.beneficiaryVASPdid || beneficiaryId) as DID,
|
|
282
273
|
role: 'SettlementAddress',
|
|
283
274
|
});
|
|
284
275
|
}
|
|
@@ -287,7 +278,8 @@ export function mapToTransactCreateRequest(
|
|
|
287
278
|
if (transaction.account.did) {
|
|
288
279
|
agents.push({
|
|
289
280
|
'@id': transaction.account.did,
|
|
290
|
-
|
|
281
|
+
// tap type needs to be updated to accept IRI as valid id
|
|
282
|
+
for: (payload.originatorVASPdid || originatorId) as DID,
|
|
291
283
|
role: 'SourceAddress',
|
|
292
284
|
});
|
|
293
285
|
}
|
|
@@ -296,7 +288,8 @@ export function mapToTransactCreateRequest(
|
|
|
296
288
|
const chainPrefix = getCaip10ChainPrefix(transaction.account.caip10);
|
|
297
289
|
agents.push({
|
|
298
290
|
'@id': `did:pkh:${chainPrefix}:${config.settlementAddress}`,
|
|
299
|
-
|
|
291
|
+
// tap type needs to be updated to accept IRI as valid id
|
|
292
|
+
for: (payload.beneficiaryVASPdid || beneficiaryId) as DID,
|
|
300
293
|
role: 'SettlementAddress',
|
|
301
294
|
});
|
|
302
295
|
}
|
|
@@ -315,12 +308,10 @@ export function mapToTransactCreateRequest(
|
|
|
315
308
|
export function mapToAppendPiiRequest(
|
|
316
309
|
transaction: Withdrawal | Deposit,
|
|
317
310
|
ivms101: IVMS101,
|
|
318
|
-
config: ResponseToIVMS101RequestConfig
|
|
311
|
+
config: ResponseToIVMS101RequestConfig & Required<BaseRequestConfig>,
|
|
319
312
|
): TransactionIVMS101Request {
|
|
320
313
|
if (isWithdrawal(transaction)) {
|
|
321
|
-
const beneficiaryId =
|
|
322
|
-
config.beneficiaryId ||
|
|
323
|
-
getPartyId('beneficiary', transaction.counterparty);
|
|
314
|
+
const beneficiaryId = config.beneficiaryId;
|
|
324
315
|
|
|
325
316
|
const beneficiaryPersons =
|
|
326
317
|
// If counterparty type is SELF, reuse originator data for beneficiary
|
|
@@ -341,8 +332,7 @@ export function mapToAppendPiiRequest(
|
|
|
341
332
|
};
|
|
342
333
|
}
|
|
343
334
|
|
|
344
|
-
const originatorId =
|
|
345
|
-
config.originatorId || getPartyId('originator', transaction.counterparty);
|
|
335
|
+
const originatorId = config.originatorId;
|
|
346
336
|
|
|
347
337
|
const originatorPersons =
|
|
348
338
|
transaction.counterparty?.type === PersonType.SELF && config.beneficiary
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { decodeJwt } from 'jose';
|
|
2
|
+
|
|
2
3
|
import {
|
|
3
4
|
PersonType,
|
|
4
5
|
type Deposit,
|
|
@@ -13,6 +14,7 @@ import {
|
|
|
13
14
|
mapToV1CreateRequest,
|
|
14
15
|
} from './mappers';
|
|
15
16
|
import type {
|
|
17
|
+
BaseRequestConfig,
|
|
16
18
|
DelegateToken,
|
|
17
19
|
ResponseToIVMS101RequestConfig,
|
|
18
20
|
ResponseToTxCreateRequestConfig,
|
|
@@ -21,7 +23,33 @@ import type {
|
|
|
21
23
|
TransactionCreateRequestV2,
|
|
22
24
|
TransactionIVMS101Request,
|
|
23
25
|
} from './types';
|
|
24
|
-
import { isDeposit, isWithdrawal } from './utils';
|
|
26
|
+
import { getPartyId, isDeposit, isWithdrawal } from './utils';
|
|
27
|
+
|
|
28
|
+
export function uuid(): string {
|
|
29
|
+
if (typeof crypto === 'undefined') {
|
|
30
|
+
throw new Error(
|
|
31
|
+
'[Notabene/SDK] Web Crypto API is not available. A secure environment with crypto support is required (Node.js 16+ or a modern browser).',
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
// Use native randomUUID when available (Node 19+, modern browsers)
|
|
35
|
+
if (typeof crypto.randomUUID === 'function') {
|
|
36
|
+
return crypto.randomUUID();
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Fallback for older environments (Node 16–18) using crypto.getRandomValues
|
|
40
|
+
return '10000000-1000-4000-8000-100000000000'.replace(/[018]/g, (c) =>
|
|
41
|
+
(
|
|
42
|
+
+c ^
|
|
43
|
+
(crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (+c / 4)))
|
|
44
|
+
).toString(16),
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// This is the format we expect for beneficiaryId and originatorId;
|
|
49
|
+
// however for now we don't use it since the backend doesn't do the check
|
|
50
|
+
// const validateIRI = (uri: string): uri is IRI => {
|
|
51
|
+
// return uri.indexOf(':') > 0;
|
|
52
|
+
// };
|
|
25
53
|
|
|
26
54
|
/**
|
|
27
55
|
* Fills in missing config values by extracting them from the delegate token and transaction data
|
|
@@ -31,7 +59,7 @@ export function enrichConfig(
|
|
|
31
59
|
config: ResponseToTxRequestConfig,
|
|
32
60
|
delegateToken: string,
|
|
33
61
|
transaction: Withdrawal | Deposit,
|
|
34
|
-
): ResponseToTxRequestConfig {
|
|
62
|
+
): ResponseToTxRequestConfig & Required<BaseRequestConfig> {
|
|
35
63
|
const enrichedConfig = { ...config };
|
|
36
64
|
|
|
37
65
|
// Extract customer ID from delegate token
|
|
@@ -42,6 +70,7 @@ export function enrichConfig(
|
|
|
42
70
|
customerIdFromToken = tokenPayload?.sub;
|
|
43
71
|
} catch {
|
|
44
72
|
// If decoding fails, customerIdFromToken remains undefined
|
|
73
|
+
// TODO: check what should we do in this scenario.
|
|
45
74
|
}
|
|
46
75
|
|
|
47
76
|
if (isWithdrawal(transaction)) {
|
|
@@ -54,9 +83,8 @@ export function enrichConfig(
|
|
|
54
83
|
if (transaction.counterparty?.type === PersonType.SELF) {
|
|
55
84
|
enrichedConfig.beneficiaryId = enrichedConfig.originatorId;
|
|
56
85
|
} else if (transaction.destination) {
|
|
57
|
-
//
|
|
58
|
-
//
|
|
59
|
-
enrichedConfig.beneficiaryId = `did:key:${transaction.destination}`;
|
|
86
|
+
// no-op: TODO: review this logic later if we need to derive beneficiaryId using a public key scheme.
|
|
87
|
+
// enrichedConfig.beneficiaryId = `did:key:${transaction.destination}`;
|
|
60
88
|
}
|
|
61
89
|
}
|
|
62
90
|
} else if (isDeposit(transaction)) {
|
|
@@ -69,14 +97,54 @@ export function enrichConfig(
|
|
|
69
97
|
if (transaction.counterparty?.type === PersonType.SELF) {
|
|
70
98
|
enrichedConfig.originatorId = enrichedConfig.beneficiaryId;
|
|
71
99
|
} else if (transaction.source) {
|
|
72
|
-
//
|
|
73
|
-
//
|
|
74
|
-
enrichedConfig.originatorId = `did:key:${transaction.source}`;
|
|
100
|
+
// no-op: TODO: review this logic later if we need to derive originatorId using a public key scheme.
|
|
101
|
+
// enrichedConfig.originatorId = `did:key:${transaction.source}`;
|
|
75
102
|
}
|
|
76
103
|
}
|
|
77
104
|
}
|
|
78
105
|
|
|
79
|
-
|
|
106
|
+
// Resolve IDs from party information (email/name) if still missing
|
|
107
|
+
if (!enrichedConfig.originatorId) {
|
|
108
|
+
const party = isWithdrawal(transaction)
|
|
109
|
+
? transaction.customer
|
|
110
|
+
: transaction.counterparty;
|
|
111
|
+
enrichedConfig.originatorId = getPartyId(party);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (!enrichedConfig.beneficiaryId) {
|
|
115
|
+
const party = isWithdrawal(transaction)
|
|
116
|
+
? transaction.counterparty
|
|
117
|
+
: transaction.customer;
|
|
118
|
+
enrichedConfig.beneficiaryId = getPartyId(party);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (!enrichedConfig.beneficiaryId) {
|
|
122
|
+
// TODO : Check if we should throw an exception instead
|
|
123
|
+
console.warn(
|
|
124
|
+
`[Notabene/SDK] beneficiaryId not provided; falling back to a generated random identifier.`,
|
|
125
|
+
);
|
|
126
|
+
enrichedConfig.beneficiaryId = `urn:uuid:${uuid()}`;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (!enrichedConfig.originatorId) {
|
|
130
|
+
// TODO : Check if we should throw an exception instead
|
|
131
|
+
console.warn(
|
|
132
|
+
`[Notabene/SDK] originatorId not provided; falling back to a generated random identifier.`,
|
|
133
|
+
);
|
|
134
|
+
enrichedConfig.originatorId = `urn:uuid:${uuid()}`;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// TODO: Re-enable IRI validation once the backend enforces it
|
|
138
|
+
// if (!validateIRI(enrichedConfig.beneficiaryId)) {
|
|
139
|
+
// throw new Error('beneficiaryId is not a valid IRI');
|
|
140
|
+
// }
|
|
141
|
+
|
|
142
|
+
// if (!validateIRI(enrichedConfig.originatorId)) {
|
|
143
|
+
// throw new Error('originatorId is not a valid IRI');
|
|
144
|
+
// }
|
|
145
|
+
|
|
146
|
+
return enrichedConfig as ResponseToTxRequestConfig &
|
|
147
|
+
Required<BaseRequestConfig>;
|
|
80
148
|
}
|
|
81
149
|
|
|
82
150
|
/**
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* These are specific to the API transformation logic
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import type { Agent, DID } from '@taprsvp/types';
|
|
6
|
+
import type { Agent, DID, IRI } from '@taprsvp/types';
|
|
7
7
|
import type { BeneficiaryV2, OriginatorV2 } from '../ivms';
|
|
8
8
|
|
|
9
9
|
export interface DelegateToken {
|
|
@@ -14,9 +14,9 @@ export interface DelegateToken {
|
|
|
14
14
|
iat?: number;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
interface BaseRequestConfig {
|
|
18
|
-
originatorId?:
|
|
19
|
-
beneficiaryId?:
|
|
17
|
+
export interface BaseRequestConfig {
|
|
18
|
+
originatorId?: IRI;
|
|
19
|
+
beneficiaryId?: IRI;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
export interface ResponseToTxCreateRequestConfig extends BaseRequestConfig {
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
import { CAIP10Schema } from '@taprsvp/types';
|
|
1
2
|
import type {
|
|
2
3
|
NaturalPersonName,
|
|
4
|
+
NaturalPersonNameV2,
|
|
3
5
|
Person,
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
import type { NaturalPersonNameV2, PersonV2 } from '../ivms';
|
|
6
|
+
PersonV2,
|
|
7
|
+
} from '../ivms';
|
|
7
8
|
import type { Deposit, Withdrawal } from '../types';
|
|
8
9
|
|
|
9
10
|
export function isDeposit(
|
|
@@ -19,21 +20,15 @@ export function isWithdrawal(
|
|
|
19
20
|
}
|
|
20
21
|
|
|
21
22
|
/**
|
|
22
|
-
*
|
|
23
|
+
* Resolves a party's IRI identifier from their email, if available.
|
|
23
24
|
*/
|
|
24
|
-
export function getPartyId(
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
): DID {
|
|
25
|
+
export function getPartyId(party?: {
|
|
26
|
+
email?: string;
|
|
27
|
+
}): `${string}:${string}` | undefined {
|
|
28
28
|
if (party?.email) {
|
|
29
|
-
return `
|
|
29
|
+
return `mailto:${party.email}`;
|
|
30
30
|
}
|
|
31
|
-
|
|
32
|
-
return `did:name:${encodeURIComponent(party.name.replace(/\s+/g, '-'))}`;
|
|
33
|
-
}
|
|
34
|
-
throw new Error(
|
|
35
|
-
`Unable to generate ${identifier} ID: missing required ${identifier} information`,
|
|
36
|
-
);
|
|
31
|
+
return undefined;
|
|
37
32
|
}
|
|
38
33
|
|
|
39
34
|
/**
|
package/src/types.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { Invoice, Party } from '@taprsvp/types';
|
|
1
2
|
import type {
|
|
2
3
|
Address,
|
|
3
4
|
Beneficiary,
|
|
@@ -23,6 +24,8 @@ export type {
|
|
|
23
24
|
NationalIdentification,
|
|
24
25
|
Originator,
|
|
25
26
|
};
|
|
27
|
+
// Re-export TAIP-16 invoice types for SDK consumers
|
|
28
|
+
export type { Invoice };
|
|
26
29
|
/**
|
|
27
30
|
* Interoperable Virtual Asset Service Provider (VASP) Messaging Standard
|
|
28
31
|
* @public
|
|
@@ -209,6 +212,7 @@ export type Source = BlockchainAddress | CAIP10;
|
|
|
209
212
|
|
|
210
213
|
/**
|
|
211
214
|
* A Uniform Resource Identifier
|
|
215
|
+
* @remarks This type will be narrowed to `` `${string}:${string}` `` in the next major release.
|
|
212
216
|
* @public
|
|
213
217
|
*/
|
|
214
218
|
export type URI = string;
|
|
@@ -617,6 +621,14 @@ export interface DepositRequestOptions {
|
|
|
617
621
|
showQrCode?: boolean; // Defaults to true
|
|
618
622
|
}
|
|
619
623
|
|
|
624
|
+
/** Output fields populated by the component on completion */
|
|
625
|
+
export interface InvoiceReaderResponse {
|
|
626
|
+
/** TAIP-16 compliant invoice data (populated by the component after PDF parsing) */
|
|
627
|
+
invoice?: Invoice;
|
|
628
|
+
merchant?: Party;
|
|
629
|
+
customer?: Party;
|
|
630
|
+
}
|
|
631
|
+
|
|
620
632
|
/**
|
|
621
633
|
* An object representing a connection request
|
|
622
634
|
* @public
|