@notabene/javascript-sdk 2.13.0 → 2.14.0-next.3

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.
@@ -0,0 +1,278 @@
1
+ import { decodeJwt } from 'jose';
2
+ import {
3
+ PersonType,
4
+ type OwnershipProof,
5
+ type TransactionResponse,
6
+ type Withdrawal,
7
+ } from '../types';
8
+ import {
9
+ mapToAppendPiiRequest,
10
+ mapToTransactCreateRequest,
11
+ mapToV1CreateRequest,
12
+ } from './mappers';
13
+ import type {
14
+ DelegateToken,
15
+ ResponseToTxRequestConfig,
16
+ TransactionCreateRequest,
17
+ TransactionCreateRequestV2,
18
+ TransactionIVMS101Request,
19
+ } from './types';
20
+
21
+ /**
22
+ * Fills in missing config values by extracting them from the delegate token and withdrawal data
23
+ * @internal
24
+ */
25
+ function enrichConfig(
26
+ config: ResponseToTxRequestConfig,
27
+ delegateToken: string,
28
+ withdrawal: Withdrawal,
29
+ ): ResponseToTxRequestConfig {
30
+ const enrichedConfig = { ...config };
31
+
32
+ // Extract originatorId from delegate token if not provided
33
+ if (!enrichedConfig.originatorId) {
34
+ try {
35
+ const tokenPayload = decodeJwt<DelegateToken>(delegateToken);
36
+ if (tokenPayload?.sub) {
37
+ enrichedConfig.originatorId = tokenPayload.sub;
38
+ }
39
+ } catch {
40
+ // If decoding fails, originatorId remains undefined
41
+ }
42
+ }
43
+
44
+ if (!enrichedConfig.beneficiaryId) {
45
+ if (withdrawal.counterparty?.type === PersonType.SELF) {
46
+ enrichedConfig.beneficiaryId = enrichedConfig.originatorId;
47
+ } else if (withdrawal.destination) {
48
+ // Generate beneficiaryId from destination if not provided.
49
+ // TODO: Replace with proper DID key identifier creation
50
+ enrichedConfig.beneficiaryId = `did:key:${withdrawal.destination}`;
51
+ }
52
+ }
53
+
54
+ return enrichedConfig;
55
+ }
56
+
57
+ /**
58
+ * Transforms a Notabene component response to a Version 1 API request body
59
+ *
60
+ * @param response - The response from the Notabene TX Create component
61
+ * @returns The transformed request body ready for the Version 1 API
62
+ *
63
+ * @example
64
+ * ```typescript
65
+ * import { componentResponseToV1TxCreateRequest } from '$lib/notabene-tx-transformer';
66
+ *
67
+ * withdrawal.on('complete', async (result) => {
68
+ * const requestBody = componentResponseToV1TxCreateRequest(result.response);
69
+ *
70
+ * await fetch(endpointUrl, {
71
+ * method: 'POST',
72
+ * body: JSON.stringify(requestBody)
73
+ * });
74
+ * });
75
+ * ```
76
+ */
77
+ export function componentResponseToV1TxCreateRequest(
78
+ response: TransactionResponse<Withdrawal>,
79
+ ): TransactionCreateRequest {
80
+ if (!response.txCreate || !response.ivms101) {
81
+ throw new Error(
82
+ 'Invalid response: missing required txCreate or ivms101 data',
83
+ );
84
+ }
85
+
86
+ const { value, ivms101, proof, txCreate } = response;
87
+
88
+ // Build withdrawal object from response data for V1 API
89
+ const withdrawal: Withdrawal = {
90
+ destination: value?.destination || '',
91
+ counterparty: value?.counterparty || {},
92
+ agent: value?.agent,
93
+ account: value?.account,
94
+ proof,
95
+ asset:
96
+ value?.asset ||
97
+ (typeof txCreate.transactionAsset === 'string'
98
+ ? txCreate.transactionAsset
99
+ : txCreate.transactionAsset?.caip19) ||
100
+ '',
101
+ amountDecimal:
102
+ value?.amountDecimal ||
103
+ (txCreate.transactionAmount ? parseFloat(txCreate.transactionAmount) : 0),
104
+ customer: value?.customer,
105
+ } as Withdrawal;
106
+
107
+ return mapToV1CreateRequest(withdrawal, txCreate, ivms101 as any);
108
+ }
109
+
110
+ /**
111
+ * Transforms a Notabene component response into txCreate, IVMS101, and confirmRelationship request bodies
112
+ *
113
+ * This is a convenience function that generates the transaction creation request,
114
+ * the IVMS101 data, and optionally the relationship confirmation proof in a single call,
115
+ * which is useful for V2 workflows where you need to create a transaction first,
116
+ * then append IVMS101 data to it, and finally confirm the relationship.
117
+ *
118
+ * @param response - The response from the Notabene Embedded Component
119
+ * @param delegateToken - The JWT delegate token for extracting the originator ID
120
+ * @param config - Optional configuration for IDs and reference
121
+ * @param config.originatorId - Optional originator ID (auto-extracted from delegateToken if not provided)
122
+ * @param config.beneficiaryId - Optional beneficiary ID (auto-generated if not provided)
123
+ * @param config.referenceId - Optional reference ID (auto-generated if not provided)
124
+ * @param config.originator - Optional originator data in V2 format
125
+ * @returns Object with `createTx`, `ivms101`, and optional `confirmRelationship` properties containing the respective request bodies
126
+ *
127
+ * @example
128
+ * ```typescript
129
+ * import { componentResponseToTxRequests } from '$lib/notabene-tx-transformer';
130
+ *
131
+ * withdrawal.on('complete', async (result) => {
132
+ * const { createTx, ivms101, confirmRelationship } = componentResponseToTxRequests(
133
+ * result.response,
134
+ * session.user.token,
135
+ * { originator: originatorData }
136
+ * );
137
+ *
138
+ * // First, create the transaction
139
+ * const txResponse = await fetch('/entity/${vaspDid}/tx', {
140
+ * method: 'POST',
141
+ * body: JSON.stringify(createTx)
142
+ * });
143
+ *
144
+ * // Then, append IVMS101 data
145
+ * const txId = txResponse.transfer['@id'];
146
+ * await fetch(`/entity/${vaspDid}/tx/${txId}/append`, {
147
+ * method: 'POST',
148
+ * body: JSON.stringify(ivms101)
149
+ * });
150
+ *
151
+ * // Finally, confirm relationship
152
+ * if (confirmRelationship) {
153
+ * await fetch(`/entity/${vaspDid}/relationship?to=${to}&from=${from}`, {
154
+ * method: 'PATCH',
155
+ * body: JSON.stringify({ proof: confirmRelationship.proof })
156
+ * });
157
+ * }
158
+ * });
159
+ * ```
160
+ */
161
+ export function componentResponseToTxRequests(
162
+ response: TransactionResponse<Withdrawal>,
163
+ delegateToken: string,
164
+ config: ResponseToTxRequestConfig = {},
165
+ ): {
166
+ createTx: TransactionCreateRequestV2;
167
+ ivms101: TransactionIVMS101Request;
168
+ confirmRelationship?: {
169
+ proof: OwnershipProof;
170
+ };
171
+ } {
172
+ if (!response.txCreate || !response.ivms101) {
173
+ throw new Error(
174
+ 'Invalid response: missing required txCreate or ivms101 data',
175
+ );
176
+ }
177
+
178
+ const { value, txCreate, ivms101, proof } = response;
179
+ const enrichedConfig = enrichConfig(config, delegateToken, value);
180
+
181
+ return {
182
+ createTx: mapToTransactCreateRequest(value, txCreate, enrichedConfig),
183
+ ivms101: mapToAppendPiiRequest(value, ivms101, enrichedConfig),
184
+ ...(proof && { confirmRelationship: { proof } }),
185
+ };
186
+ }
187
+
188
+ /**
189
+ * Transforms a Notabene component response to a Version 2 transaction create API request body
190
+ *
191
+ * @param response - The response from the Notabene Embedded Component
192
+ * @param delegateToken - The JWT delegate token for extracting the originator ID
193
+ * @param config - Configuration object with optional IDs
194
+ * @param config.originatorId - Optional originator ID (auto-extracted from delegateToken if not provided)
195
+ * @param config.beneficiaryId - Optional beneficiary ID (auto-generated if not provided)
196
+ * @param config.referenceId - Optional reference ID for the transaction
197
+ * @returns The transformed request body ready for the Version 2 transaction create API
198
+ *
199
+ * @example
200
+ * ```typescript
201
+ * import { componentResponseToTxCreateRequest } from '$lib/notabene-tx-transformer';
202
+ *
203
+ * withdrawal.on('complete', async (result) => {
204
+ * const requestBody = componentResponseToTxCreateRequest(
205
+ * result.response,
206
+ * {
207
+ * originatorId: 'mailto:user@example.com',
208
+ * beneficiaryId: 'urn:beneficiary:recipient',
209
+ * referenceId: 'tx-12345'
210
+ * }
211
+ * );
212
+ *
213
+ * await fetch('/entity/${vaspDid}/tx', {
214
+ * method: 'POST',
215
+ * body: JSON.stringify(requestBody)
216
+ * });
217
+ * });
218
+ * ```
219
+ */
220
+ export function componentResponseToTxCreateRequest(
221
+ response: TransactionResponse<Withdrawal>,
222
+ delegateToken: string,
223
+ config: Omit<ResponseToTxRequestConfig, 'originator'> = {},
224
+ ) {
225
+ if (!response.txCreate || !response.ivms101) {
226
+ throw new Error(
227
+ 'Invalid response: missing required txCreate or ivms101 data',
228
+ );
229
+ }
230
+
231
+ const { value, txCreate } = response;
232
+ const enrichedConfig = enrichConfig(config, delegateToken, value);
233
+
234
+ return mapToTransactCreateRequest(value, txCreate, enrichedConfig);
235
+ }
236
+
237
+ /**
238
+ * Transforms a Notabene component response to IVMS101 format
239
+ *
240
+ * @param response - The response from the Notabene Embedded Component
241
+ * @param delegateToken - The JWT delegate token for extracting the originator ID
242
+ * @param config - Configuration object with optional IDs
243
+ * @param config.originatorId - Optional originator ID (auto-extracted from delegateToken if not provided)
244
+ * @param config.beneficiaryId - Optional beneficiary ID (auto-generated if not provided)
245
+ * @param config.referenceId - Optional reference ID for the transaction
246
+ * @param config.originator - Optional originator data in V2 format
247
+ * @returns The transformed request body in IVMS101 format
248
+ *
249
+ * @example
250
+ * ```typescript
251
+ * import { componentResponseToIVMS101 } from '$lib/notabene-tx-transformer';
252
+ *
253
+ * const requestBody = componentResponseToIVMS101(
254
+ * result.response,
255
+ * session.user.token,
256
+ * { originator: myOriginatorData }
257
+ * );
258
+ *
259
+ * await fetch('/entity/${vaspDid}/tx/${txId}/append', {
260
+ * method: 'POST',
261
+ * body: JSON.stringify(requestBody)
262
+ * });
263
+ * ```
264
+ */
265
+ export function componentResponseToIVMS101(
266
+ response: TransactionResponse<Withdrawal>,
267
+ delegateToken: string,
268
+ config: ResponseToTxRequestConfig = {},
269
+ ) {
270
+ if (!response.ivms101) {
271
+ throw new Error('Invalid response: missing required ivms101 data');
272
+ }
273
+
274
+ const { value, ivms101 } = response;
275
+ const enrichedConfig = enrichConfig(config, delegateToken, value);
276
+
277
+ return mapToAppendPiiRequest(value, ivms101, enrichedConfig);
278
+ }
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Types that are not available in @notabene/javascript-sdk
3
+ * These are specific to the API transformation logic
4
+ */
5
+
6
+ import type { Agent, DID } from '@taprsvp/types';
7
+ import type { BeneficiaryV2, OriginatorV2 } from '../ivms';
8
+
9
+ export interface DelegateToken {
10
+ sub?: DID;
11
+ iss?: DID;
12
+ scope?: 'delegate';
13
+ exp?: number;
14
+ iat?: number;
15
+ }
16
+
17
+ export interface ResponseToTxRequestConfig {
18
+ originatorId?: DID;
19
+ beneficiaryId?: DID;
20
+ referenceId?: string;
21
+ originator?: OriginatorV2;
22
+ }
23
+
24
+ export interface TransactionCreateRequest {
25
+ transactionAsset: any;
26
+ transactionAmount: string;
27
+ beneficiaryDid?: string;
28
+ originatorVASPdid: string;
29
+ beneficiaryVASPdid?: string;
30
+ beneficiaryVASPname?: string;
31
+ beneficiaryVASPwebsite?: string;
32
+ transactionBlockchainInfo: {
33
+ origin?: string;
34
+ destination?: string;
35
+ };
36
+ beneficiaryProof?: any;
37
+ beneficiary?: any;
38
+ originator?: any;
39
+ originatorEqualsBeneficiary?: boolean;
40
+ }
41
+
42
+ export interface TransactionCreateRequestV2 {
43
+ originator: {
44
+ '@id': string;
45
+ };
46
+ beneficiary: {
47
+ '@id': string;
48
+ };
49
+ asset: string;
50
+ amount: string;
51
+ agents: Agent[];
52
+ ref: string;
53
+ }
54
+
55
+ export interface TransactionIVMS101Request {
56
+ ivms101: {
57
+ originator?: OriginatorV2;
58
+ beneficiary?: BeneficiaryV2;
59
+ };
60
+ }
@@ -0,0 +1,61 @@
1
+ import type {
2
+ NaturalPersonName,
3
+ Person,
4
+ } from '@notabene/javascript-sdk/src/ivms/types';
5
+ import type { DID } from '@taprsvp/types';
6
+ import type { NaturalPersonNameV2, PersonV2 } from '../ivms';
7
+
8
+ /**
9
+ * Generates a backup DID identifier for a party
10
+ */
11
+ export function getPartyId(
12
+ identifier: 'originator' | 'beneficiary',
13
+ party?: { email?: string; name?: string },
14
+ ): DID {
15
+ if (party?.email) {
16
+ return `did:email:${party.email}`;
17
+ }
18
+ if (party?.name) {
19
+ return `did:name:${encodeURIComponent(party.name.replace(/\s+/g, '-'))}`;
20
+ }
21
+ throw new Error(
22
+ `Unable to generate ${identifier} ID: missing required ${identifier} information`,
23
+ );
24
+ }
25
+
26
+ /**
27
+ * Converts NaturalPersonName from V1 format to V2 format
28
+ * Changes the nameIdentifierType field name to naturalPersonNameIdentifierType
29
+ */
30
+ export function convertNaturalPersonNameToV2(
31
+ name: NaturalPersonName,
32
+ ): NaturalPersonNameV2 {
33
+ const { nameIdentifier, ...rest } = name;
34
+ return {
35
+ ...rest,
36
+ nameIdentifier: nameIdentifier?.map(({ nameIdentifierType, ...rest }) => ({
37
+ ...rest,
38
+ naturalPersonNameIdentifierType: nameIdentifierType,
39
+ })),
40
+ };
41
+ }
42
+
43
+ /**
44
+ * Converts a Person from V1 format to V2 format
45
+ * Applies deep conversion to natural person names and adds account number
46
+ */
47
+ export function convertPersonToV2(
48
+ person: Person,
49
+ accountNumber: string,
50
+ ): PersonV2 {
51
+ return {
52
+ naturalPerson: person.naturalPerson
53
+ ? {
54
+ ...person.naturalPerson,
55
+ name: convertNaturalPersonNameToV2(person.naturalPerson.name),
56
+ }
57
+ : undefined,
58
+ legalPerson: person.legalPerson,
59
+ accountNumber: [accountNumber],
60
+ };
61
+ }
package/src/types.ts CHANGED
@@ -888,6 +888,7 @@ export interface TransactionOptions {
888
888
  vasps?: VASPOptions;
889
889
  hide?: ValidationSections[]; // You can hide a specific section of the component by listing it here
890
890
  counterpartyAssist?: CounterpartyAssistConfig;
891
+ autoSubmit?: boolean; // Defaults to false
891
892
  }
892
893
  /**
893
894
  * Component Message Type enum representing different message types that can be sent