@notabene/javascript-sdk 1.32.0 → 2.0.0-next.2

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.
Files changed (74) hide show
  1. package/.gitlab-ci.yml +12 -1
  2. package/.husky/commit-msg +0 -0
  3. package/.husky/pre-commit +0 -0
  4. package/.husky/pre-push +1 -1
  5. package/.vscode/extensions.json +1 -5
  6. package/.vscode/settings.json +4 -4
  7. package/.yarn/releases/yarn-berry.cjs +925 -0
  8. package/.yarnrc.yml +3 -0
  9. package/CODEOWNERS +1 -1
  10. package/README.md +128 -70
  11. package/api-extractor.json +434 -0
  12. package/dist/notabene.cjs +1 -0
  13. package/dist/notabene.d.ts +678 -0
  14. package/dist/notabene.js +187 -0
  15. package/dist/tsdoc-metadata.json +11 -0
  16. package/eslint.config.js +24 -0
  17. package/etc/javascript-sdk.api.md +363 -0
  18. package/index.html +137 -0
  19. package/package.json +27 -53
  20. package/src/__tests__/notabene.test.ts +116 -0
  21. package/src/arbitraries.ts +13 -0
  22. package/src/components/EmbeddedComponent.ts +110 -0
  23. package/src/components/__tests__/EmbeddedComponent.test.ts +160 -0
  24. package/src/ivms/types.ts +2 -0
  25. package/src/notabene.ts +173 -279
  26. package/src/types.ts +381 -49
  27. package/src/utils/MessageEventManager.ts +55 -0
  28. package/src/utils/__tests__/MessageEventManager.test.ts +95 -0
  29. package/src/utils/arbitraries.ts +21 -0
  30. package/src/utils/caip.ts +16 -0
  31. package/src/utils/urls.ts +15 -0
  32. package/temp/javascript-sdk.api.json +3509 -0
  33. package/temp/javascript-sdk.api.md +363 -0
  34. package/ts-out/src/__tests__/notabene.test.d.ts +1 -0
  35. package/ts-out/src/__tests__/notabene.test.js +88 -0
  36. package/ts-out/src/arbitraries.d.ts +4 -0
  37. package/ts-out/src/arbitraries.js +8 -0
  38. package/ts-out/src/components/EmbeddedComponent.d.ts +25 -0
  39. package/ts-out/src/components/EmbeddedComponent.js +87 -0
  40. package/ts-out/src/components/__tests__/EmbeddedComponent.test.d.ts +1 -0
  41. package/ts-out/src/components/__tests__/EmbeddedComponent.test.js +132 -0
  42. package/ts-out/src/ivms/types.d.ts +252 -0
  43. package/ts-out/src/ivms/types.js +1 -0
  44. package/ts-out/src/notabene.d.ts +35 -0
  45. package/ts-out/src/notabene.js +59 -0
  46. package/ts-out/src/types.d.ts +357 -0
  47. package/ts-out/src/types.js +85 -0
  48. package/ts-out/src/utils/MessageEventManager.d.ts +12 -0
  49. package/ts-out/src/utils/MessageEventManager.js +45 -0
  50. package/ts-out/src/utils/__tests__/MessageEventManager.test.d.ts +1 -0
  51. package/ts-out/src/utils/__tests__/MessageEventManager.test.js +73 -0
  52. package/ts-out/src/utils/arbitraries.d.ts +6 -0
  53. package/ts-out/src/utils/arbitraries.js +7 -0
  54. package/ts-out/src/utils/caip.d.ts +13 -0
  55. package/ts-out/src/utils/caip.js +15 -0
  56. package/ts-out/src/utils/urls.d.ts +1 -0
  57. package/ts-out/src/utils/urls.js +14 -0
  58. package/ts-out/tsconfig.tsbuildinfo +1 -0
  59. package/tsconfig.json +15 -11
  60. package/tsconfig.tsbuildinfo +1 -0
  61. package/vite.config.js +13 -0
  62. package/.envrc.template +0 -1
  63. package/.eslintignore +0 -3
  64. package/.eslintrc.js +0 -13
  65. package/.nvmrc +0 -1
  66. package/.tool-versions +0 -3
  67. package/dist/es/index.js +0 -1
  68. package/dist/lib/index.js +0 -366
  69. package/jest.config.js +0 -5
  70. package/public/index.html +0 -93
  71. package/public/js/.gitkeep +0 -0
  72. package/src/lib/index.ts +0 -2
  73. package/src/module/index.ts +0 -10
  74. package/src/zoidComponentProps.ts +0 -81
package/src/types.ts CHANGED
@@ -1,5 +1,43 @@
1
- import { DateAndPlaceOfBirth, NationalIdentification } from 'ivms/types';
1
+ import {
2
+ DateAndPlaceOfBirth,
3
+ IVMS101,
4
+ NationalIdentification,
5
+ } from './ivms/types';
2
6
 
7
+ export type { IVMS101 };
8
+
9
+ export type CAIP2 = string;
10
+ export type CAIP10 = string;
11
+ export type CAIP19 = string;
12
+ export type CAIP220 = string;
13
+
14
+ export type DTI = string;
15
+ export type NotabeneAsset = string;
16
+
17
+ /**
18
+ * The asset of a transaction either a Notabene asset, a CAIP-19 asset, or a DTI.
19
+ *
20
+ * @public
21
+ */
22
+
23
+ export type TransactionAsset = NotabeneAsset | CAIP19 | DTI;
24
+
25
+ export type BlockchainAddress = string;
26
+ export type TravelAddress = string;
27
+
28
+ /**
29
+ * The destination of a transaction either a blockchain address, a CAIP-19 address, or a travel address.
30
+ * @public
31
+ */
32
+ export type Destination = BlockchainAddress | CAIP19 | TravelAddress;
33
+ export type Source = BlockchainAddress | CAIP19;
34
+ export type URI = string;
35
+ export type DID = string;
36
+
37
+ /**
38
+ * The theme of the Notabene SDK
39
+ * @public
40
+ */
3
41
  export type Theme = {
4
42
  primaryColor: string;
5
43
  secondaryColor: string;
@@ -7,21 +45,44 @@ export type Theme = {
7
45
  logo: string;
8
46
  };
9
47
 
10
- export enum WidgetType {
11
- WITHDRAWAL = 'WITHDRAWAL',
12
- POST_DEPOSIT = 'POST_DEPOSIT',
48
+ export enum ComponentTypes {
49
+ WITHDRAW_ASSIST = 'WITHDRAW_ASSIST',
13
50
  }
14
51
 
52
+ export type TransactionType = 'VASP_2_VASP' | 'SELF_HOSTED';
53
+
15
54
  export type TransactionTypeAllowed =
16
55
  | 'ALL'
17
56
  | 'VASP_2_VASP_ONLY'
18
- | 'SELF_TRANSACTION_ONLY';
57
+ | 'FIRST_PARTY_ONLY';
19
58
 
20
59
  export type NonCustodialDeclarationType =
21
60
  | 'SIGNATURE'
22
61
  | 'DECLARATION'
23
62
  | 'SIGNATURE_AND_DECLARATION';
24
63
 
64
+ /**
65
+ * The type of Agent. Either a wallet or a VASP
66
+ * @public
67
+ */
68
+
69
+ export enum AgentType {
70
+ PRIVATE = 'WALLET',
71
+ VASP = 'VASP',
72
+ }
73
+
74
+ /**
75
+ * Who is the agent acting on behalf of the counterparty
76
+ * @public
77
+ */
78
+ export declare interface Agent {
79
+ did: DID;
80
+ type: AgentType;
81
+ logo?: string;
82
+ url?: string;
83
+ name?: string;
84
+ verified?: boolean;
85
+ }
25
86
  export type OwnershipProofInput = {
26
87
  type?: string | null;
27
88
  proof?: string | null;
@@ -37,55 +98,134 @@ export type CountryType = {
37
98
  name: string;
38
99
  };
39
100
 
40
- export type PersonType = 'natural' | 'legal';
101
+ /**
102
+ * The type of counterparty. Either a natural person or a legal person. If the customer is the same as the counterparty then the counterparty is a self.
103
+ * @public
104
+ */
105
+ export enum PersonType {
106
+ NATURAL = 'natural',
107
+ LEGAL = 'legal',
108
+ SELF = 'self', // first party
109
+ }
110
+
111
+ /**
112
+ * A VASP agent acting on behalf of the counterparty
113
+ * @public
114
+ */
115
+ export interface VASP extends Agent {
116
+ url?: string;
117
+ name?: string;
118
+ }
119
+ /**
120
+ * A wallet agent acting on behalf of the counterparty
121
+ * @public
122
+ */
123
+ export interface Wallet extends Agent {
124
+ proof: OwnershipProof;
125
+ wallet_connect_id?: string;
126
+ }
127
+
128
+ /**
129
+ * The counterparty of a transaction.
130
+ * @public
131
+ */
132
+ export interface Counterparty {
133
+ name?: string;
134
+ accountNumber?: string;
135
+ did?: string;
136
+ geographicAddress?: string;
137
+ type?: PersonType;
138
+ verified?: boolean;
139
+ }
140
+ /**
141
+ * A counterparty object representing a natural person
142
+ * @public
143
+ */
144
+ export interface NaturalPerson extends Counterparty {
145
+ type: PersonType.NATURAL;
146
+ nationalIdentification?: NationalIdentification;
147
+ dateAndPlaceOfBirth?: DateAndPlaceOfBirth;
148
+ name: string;
149
+ }
150
+
151
+ /**
152
+ * A counterparty object representing a legal person
153
+ * @public
154
+ */
155
+ export interface LegalPerson extends Counterparty {
156
+ type: PersonType.LEGAL;
157
+ name: string;
158
+ lei?: string;
159
+ url?: string;
160
+ logo?: string;
161
+ }
41
162
 
42
163
  export type OriginatorFields = {
43
- originatorAccountNumber?: string;
44
- originatorDid?: string;
45
- originatorVASPname?: string;
46
- originatorVASPdid?: string;
47
- originatorName?: string;
48
- originatorGeographicAddress?: string;
49
- originatorNationalIdentification?: NationalIdentification;
50
- originatorDateAndPlaceOfBirth?: DateAndPlaceOfBirth;
51
- originatorPersonType?: PersonType;
164
+ source?: Source;
52
165
  };
53
166
 
54
167
  export type BeneficiaryFields = {
55
- beneficiaryAccountNumber?: string;
56
- beneficiaryDid?: string;
57
- beneficiaryVASPname?: string;
58
- beneficiaryVASPdid?: string;
59
- beneficiaryName?: string;
60
- beneficiaryGeographicAddress?: string;
61
- beneficiaryNationalIdentification?: NationalIdentification;
62
- beneficiaryDateAndPlaceOfBirth?: DateAndPlaceOfBirth;
63
- beneficiaryPersonType?: PersonType;
64
- };
65
-
66
- export type CAIP19 = {
67
- caip19: string;
68
- };
69
-
70
- export type CoingeckoIdAndNetwork = { coingeckoId: string; network: string };
71
-
72
- export type TransactionAsset = string | CAIP19 | CoingeckoIdAndNetwork;
73
- export type Transaction = OriginatorFields &
74
- BeneficiaryFields & {
75
- transactionAsset: TransactionAsset;
76
- transactionAmount: string;
77
- transactionBlockchainInfo?: TransactionBlockchainInfo;
78
- customAssetPrice?: {
79
- priceUSD: number;
80
- decimals: number;
81
- };
82
- isNonCustodial?: boolean;
83
- originatorEqualsBeneficiary?: boolean;
84
- beneficiaryProof?: OwnershipProofInput;
85
- originatorProof?: OwnershipProofInput;
86
- isValid?: boolean;
87
- errors?: string[];
168
+ destination?: Destination;
169
+ };
170
+
171
+ /**
172
+ * An abstract transaction object
173
+ * @public
174
+ */
175
+ export interface Transaction {
176
+ agent: Agent;
177
+ customer?: Counterparty;
178
+ counterparty: Counterparty;
179
+ asset: TransactionAsset;
180
+ amountDecimal: number;
181
+ // transactionBlockchainInfo?: TransactionBlockchainInfo;
182
+ customAssetPrice?: {
183
+ price: number;
184
+ currency: string;
88
185
  };
186
+ }
187
+
188
+ /**
189
+ * An object representing a withdrawal transaction
190
+ * @public
191
+ */
192
+ export interface Withdrawal extends BeneficiaryFields, Transaction {}
193
+ /**
194
+ * An object representing a deposit transaction
195
+ * @public
196
+ */
197
+ export interface Deposit extends OriginatorFields, Transaction {}
198
+
199
+ /**
200
+ * The verification status of a transaction
201
+ * @public
202
+ */
203
+ export enum Status {
204
+ EMPTY = 'empty',
205
+ VERIFY = 'verify',
206
+ PENDING = 'pending',
207
+ VERIFIED = 'verified',
208
+ BANNED = 'banned',
209
+ }
210
+
211
+ /**
212
+ * The response of a transaction
213
+ * @public
214
+ */
215
+
216
+ export type TransactionResponse = {
217
+ value: Transaction;
218
+ ivms: IVMS101;
219
+ proof?: OwnershipProof;
220
+ valid: boolean;
221
+ status: Status;
222
+ errors: ValidationError[];
223
+ };
224
+
225
+ export type ValidationError = {
226
+ attribute: string;
227
+ message: string;
228
+ };
89
229
 
90
230
  export type FieldProps = {
91
231
  forceDisplay?: boolean; // instead of beneficiaryDetails - defaults to false
@@ -95,6 +235,7 @@ export type FieldProps = {
95
235
  export type FieldName =
96
236
  | 'counterparty'
97
237
  | 'geographicAddress'
238
+ | 'firstName'
98
239
  | 'name'
99
240
  | 'nationalIdentification'
100
241
  | 'dateAndPlaceOfBirth';
@@ -103,7 +244,7 @@ export type FieldsProps = {
103
244
  [name in FieldName]?: FieldProps;
104
245
  };
105
246
 
106
- type WalletNotSupportedFlow = {
247
+ export type WalletNotSupportedFlow = {
107
248
  flow: 'WALLET_NOT_SUPPORTED';
108
249
  action: 'DECLARATION' | 'REJECT';
109
250
  };
@@ -112,3 +253,194 @@ type WalletNotSupportedFlow = {
112
253
  export type Fallback = WalletNotSupportedFlow;
113
254
 
114
255
  export type OptInFeature = 'REUSE_ADDRESS_OWNERSHIP_PROOF';
256
+
257
+ /**
258
+ * Component Message Types
259
+ * @internal
260
+ */
261
+ export const enum CMType {
262
+ COMPLETE = 'complete',
263
+ RESIZE = 'resize',
264
+ RESULT = 'result',
265
+ READY = 'ready',
266
+ INVALID = 'invalid',
267
+ MODAL = 'openModal',
268
+ ERROR = 'error',
269
+ CLOSE = 'closeModal',
270
+ CANCEL = 'cancel',
271
+ }
272
+
273
+ export type Completed = {
274
+ type: CMType.COMPLETE;
275
+ response: TransactionResponse;
276
+ };
277
+
278
+ export type Result = {
279
+ type: CMType.RESULT;
280
+ reqid: RequestID;
281
+ response: TransactionResponse;
282
+ };
283
+
284
+ export type Ready = {
285
+ type: CMType.READY;
286
+ };
287
+
288
+ export type ResizeRequest = {
289
+ type: CMType.RESIZE;
290
+ height: number;
291
+ };
292
+
293
+ export type Error = {
294
+ type: CMType.ERROR;
295
+ message: string;
296
+ };
297
+
298
+ export type ModalRequest = {
299
+ type: CMType.MODAL;
300
+ url: string;
301
+ reqid: RequestID;
302
+ };
303
+
304
+ export type CloseModal = {
305
+ type: CMType.CLOSE;
306
+ reqid: RequestID;
307
+ };
308
+
309
+ export type Cancel = {
310
+ type: CMType.CANCEL;
311
+ };
312
+
313
+ export type InvalidValue = {
314
+ type: CMType.INVALID;
315
+ value: any;
316
+ errors: ValidationError[];
317
+ };
318
+
319
+ /**
320
+ * Component Message
321
+ * @internal
322
+ */
323
+ export type ComponentMessage =
324
+ | Completed
325
+ | Cancel
326
+ | Error
327
+ | Result
328
+ | Ready
329
+ | ResizeRequest
330
+ | ModalRequest
331
+ | InvalidValue
332
+ | CloseModal;
333
+
334
+ export type RequestID = string;
335
+
336
+ /**
337
+ * Host Message Types
338
+ * @internal
339
+ */
340
+
341
+ export const enum HMType {
342
+ UPDATE = 'update',
343
+ REQUEST_RESPONSE = 'requestResponse',
344
+ }
345
+
346
+ export type UpdateValue = {
347
+ type: HMType.UPDATE;
348
+ value: Partial<Transaction>;
349
+ };
350
+
351
+ export type RequestResponse = {
352
+ type: HMType.REQUEST_RESPONSE;
353
+ reqid: RequestID;
354
+ };
355
+
356
+ /**
357
+ * Host Messages
358
+ * @internal
359
+ */
360
+
361
+ export type HostMessage = UpdateValue | RequestResponse;
362
+
363
+ export interface CallbackOptions {
364
+ callback?: URI;
365
+ redirectUri?: URI;
366
+ }
367
+
368
+ /**
369
+ * Status of the proof
370
+ * @public
371
+ */
372
+ export enum ProofStatus {
373
+ PENDING = 'pending', // Verification is pending
374
+ FAILED = 'rejected', // Rejected
375
+ FLAGGED = 'flagged', // Flagged for manual review
376
+ VERIFIED = 'verified', // Verified
377
+ }
378
+
379
+ /**
380
+ * The type of Proofs supported
381
+ * @public
382
+ **/
383
+ export enum ProofTypes {
384
+ SelfDeclaration = 'self-declaration',
385
+ PersonalSignEIP191 = 'eip-191',
386
+ PersonalSignEIP712 = 'eip-712',
387
+ PersonalSignBIP137 = 'bip-137',
388
+ PersonalSignXPUB = 'xpub',
389
+ MicroTransfer = 'microtransfer',
390
+ Screenshot = 'screenshot',
391
+ }
392
+ /**
393
+ * Ownership Proof
394
+ * @public
395
+ */
396
+ export interface OwnershipProof {
397
+ type: ProofTypes;
398
+ status: ProofStatus;
399
+ did: DID;
400
+ address: CAIP10;
401
+ }
402
+
403
+ /**
404
+ * Ownership Proof using Message Signature
405
+ * @public
406
+ */
407
+ export interface SignatureProof extends OwnershipProof {
408
+ type:
409
+ | ProofTypes.PersonalSignEIP191
410
+ | ProofTypes.PersonalSignEIP712
411
+ | ProofTypes.PersonalSignBIP137
412
+ | ProofTypes.PersonalSignXPUB;
413
+ proof: string;
414
+ attestation: string;
415
+ wallet_provider: string;
416
+ }
417
+
418
+ /**
419
+ * Ownership Proof using Self Declaration
420
+ * @public
421
+ */
422
+ export interface DeclarationProof extends OwnershipProof {
423
+ type: ProofTypes.SelfDeclaration;
424
+ attestation: string;
425
+ confirmed: boolean;
426
+ }
427
+
428
+ /**
429
+ * Ownership Proof using Micro Transfer
430
+ * @public
431
+ */
432
+ export interface MicroTransferProof extends OwnershipProof {
433
+ type: ProofTypes.MicroTransfer;
434
+ txhash: string;
435
+ chain: CAIP2;
436
+ amount: number;
437
+ }
438
+
439
+ /**
440
+ * Ownership Proof using Screenshot
441
+ * @public
442
+ */
443
+ export interface ScreenshotProof extends OwnershipProof {
444
+ type: ProofTypes.Screenshot;
445
+ url: string;
446
+ }
@@ -0,0 +1,55 @@
1
+ import { ComponentMessage, HostMessage } from '../types';
2
+
3
+ export type MessageCallback = (message: ComponentMessage) => void;
4
+
5
+ export class MessageEventManager {
6
+ private listeners: Map<string, Set<MessageCallback>> = new Map();
7
+ private port?: MessagePort;
8
+
9
+ constructor() {
10
+ this.handleMessage = this.handleMessage.bind(this);
11
+ }
12
+
13
+ setPort(port: MessagePort): void {
14
+ this.port = port;
15
+ this.port.onmessage = this.handleMessage;
16
+ this.port.start();
17
+ }
18
+
19
+ on(messageType: string, callback: MessageCallback): void {
20
+ if (!this.listeners.has(messageType)) {
21
+ this.listeners.set(messageType, new Set());
22
+ }
23
+ this.listeners.get(messageType)!.add(callback);
24
+ }
25
+
26
+ off(messageType: string, callback: MessageCallback): void {
27
+ const callbacks = this.listeners.get(messageType);
28
+ if (callbacks) {
29
+ callbacks.delete(callback);
30
+ if (callbacks.size === 0) {
31
+ this.listeners.delete(messageType);
32
+ }
33
+ }
34
+ }
35
+
36
+ private handleMessage(event: MessageEvent): void {
37
+ console.log('received message', event.data);
38
+ const message = event.data;
39
+ if (typeof message === 'object' && message !== null && 'type' in message) {
40
+ const messageType = message.type as string;
41
+ const callbacks = this.listeners.get(messageType);
42
+ if (callbacks) {
43
+ callbacks.forEach((callback) => callback(message));
44
+ }
45
+ }
46
+ }
47
+
48
+ // Method to send messages through the port
49
+ send(message: HostMessage): void {
50
+ if (!this.port) {
51
+ throw new Error('No port set');
52
+ }
53
+ this.port.postMessage(message);
54
+ }
55
+ }
@@ -0,0 +1,95 @@
1
+ import { beforeEach, describe, expect, it, vi } from 'vitest';
2
+ import { HMType, UpdateValue } from '../../types';
3
+ import { MessageEventManager } from '../MessageEventManager';
4
+
5
+ describe('MessageEventManager', () => {
6
+ let messageEventManager: MessageEventManager;
7
+ let mockPort: MessagePort;
8
+
9
+ beforeEach(() => {
10
+ mockPort = {
11
+ onmessage: null,
12
+ postMessage: vi.fn(),
13
+ start: vi.fn(),
14
+ } as unknown as MessagePort;
15
+
16
+ messageEventManager = new MessageEventManager();
17
+ });
18
+
19
+ describe('setPort', () => {
20
+ beforeEach(() => {
21
+ messageEventManager.setPort(mockPort);
22
+ });
23
+
24
+ it('should start the port when initialized', () => {
25
+ expect(mockPort.start).toHaveBeenCalled();
26
+ });
27
+
28
+ it('should subscribe and receive messages of a specific type', () => {
29
+ const readyHandler = vi.fn();
30
+ messageEventManager.on('ready', readyHandler);
31
+
32
+ const readyMessage = { type: 'ready' };
33
+ mockPort.onmessage!({ data: readyMessage } as MessageEvent);
34
+
35
+ expect(readyHandler).toHaveBeenCalledWith(readyMessage);
36
+ });
37
+
38
+ it('should not call handlers for different message types', () => {
39
+ const updateHandler = vi.fn();
40
+ const errorHandler = vi.fn();
41
+ messageEventManager.on('update', updateHandler);
42
+ messageEventManager.on('error', errorHandler);
43
+
44
+ const errorMessage = { type: 'error', message: 'Something went wrong' };
45
+ mockPort.onmessage!({ data: errorMessage } as MessageEvent);
46
+
47
+ expect(updateHandler).not.toHaveBeenCalled();
48
+ expect(errorHandler).toHaveBeenCalledWith(errorMessage);
49
+ });
50
+
51
+ it('should unsubscribe handlers', () => {
52
+ const updateHandler = vi.fn();
53
+ messageEventManager.on('update', updateHandler);
54
+ messageEventManager.off('update', updateHandler);
55
+
56
+ const updateMessage = { type: 'update', data: { foo: 'bar' } };
57
+ mockPort.onmessage!({ data: updateMessage } as MessageEvent);
58
+
59
+ expect(updateHandler).not.toHaveBeenCalled();
60
+ });
61
+
62
+ it('should allow multiple subscribers for the same message type', () => {
63
+ const updateHandler1 = vi.fn();
64
+ const updateHandler2 = vi.fn();
65
+ messageEventManager.on('update', updateHandler1);
66
+ messageEventManager.on('update', updateHandler2);
67
+
68
+ const updateMessage = { type: 'update', data: { foo: 'bar' } };
69
+ mockPort.onmessage!({ data: updateMessage } as MessageEvent);
70
+
71
+ expect(updateHandler1).toHaveBeenCalledWith(updateMessage);
72
+ expect(updateHandler2).toHaveBeenCalledWith(updateMessage);
73
+ });
74
+
75
+ it('should send messages through the port', () => {
76
+ const message: UpdateValue = {
77
+ type: HMType.UPDATE,
78
+ value: { asset: 'USDC' },
79
+ };
80
+ messageEventManager.send(message);
81
+
82
+ expect(mockPort.postMessage).toHaveBeenCalledWith(message);
83
+ });
84
+
85
+ it('should ignore messages without a type', () => {
86
+ const handler = vi.fn();
87
+ messageEventManager.on('update', handler);
88
+
89
+ const invalidMessage = { data: 'no type field' };
90
+ mockPort.onmessage!({ data: invalidMessage } as MessageEvent);
91
+
92
+ expect(handler).not.toHaveBeenCalled();
93
+ });
94
+ });
95
+ });
@@ -0,0 +1,21 @@
1
+ import fc from 'fast-check';
2
+ import type { CAIP10, CAIP19, CAIP2, CAIP220 } from '../types';
3
+ import {
4
+ CAIP10_MATCHER,
5
+ CAIP19_MATCHER,
6
+ CAIP220_MATCHER,
7
+ CAIP2_MATCHER,
8
+ } from './caip';
9
+
10
+ // Arbitraries
11
+ export const arbitraryCAIP10 = (): fc.Arbitrary<CAIP10> =>
12
+ fc.stringMatching(CAIP10_MATCHER);
13
+
14
+ export const arbitraryCAIP2 = (): fc.Arbitrary<CAIP2> =>
15
+ fc.stringMatching(CAIP2_MATCHER);
16
+
17
+ export const arbitraryCAIP19 = (): fc.Arbitrary<CAIP19> =>
18
+ fc.stringMatching(CAIP19_MATCHER);
19
+
20
+ export const arbitraryCAIP220 = (): fc.Arbitrary<CAIP220> =>
21
+ fc.stringMatching(CAIP220_MATCHER);
@@ -0,0 +1,16 @@
1
+ // Regexes
2
+ export const ACCOUNT_ADDRESS_REGEX = '[-.%a-zA-Z0-9]{1,128}';
3
+ export const CAIP2_REGEX = '[-a-z0-9]{3,8}:[-_a-zA-Z0-9]{1,32}';
4
+ export const CAIP10_REGEX = `^${CAIP2_REGEX}:${ACCOUNT_ADDRESS_REGEX}$`;
5
+ export const CAIP19_REGEX = `^${CAIP2_REGEX}/[-a-z0-9]{3,8}:[-.%a-zA-Z0-9]{1,128}(/[-.%a-zA-Z0-9]{1,78})?$`;
6
+ export const CAIP220_REGEX = `^${CAIP2_REGEX}:[block:]?tx/[-.%a-zA-Z0-9]{1,128}$`;
7
+ export const CRYPTO_SYMBOL_REGEX = '^[A-Z0-9]{2,10}$';
8
+ export const DTI_REGEX = '^[A-Za-z0-9]{10}$';
9
+ export const COMBINED_ASSET_REGEX = `(${CRYPTO_SYMBOL_REGEX})|(${CAIP19_REGEX})|(${DTI_REGEX})`;
10
+
11
+ // Matchers
12
+ export const CAIP2_MATCHER = new RegExp(CAIP2_REGEX);
13
+ export const CAIP10_MATCHER = new RegExp(CAIP10_REGEX);
14
+ export const CAIP19_MATCHER = new RegExp(CAIP19_REGEX);
15
+ export const CAIP220_MATCHER = new RegExp(CAIP220_REGEX);
16
+ export const COMBINED_ASSET_MATCHER = new RegExp(COMBINED_ASSET_REGEX);
@@ -0,0 +1,15 @@
1
+ export function encodeObjectToFragment(obj: any) {
2
+ return Object.entries(obj)
3
+ .map(([key, value]) => {
4
+ if (!(key && value)) return undefined;
5
+ const encodedKey = encodeURIComponent(key);
6
+ const encodedValue = encodeURIComponent(
7
+ typeof value === 'object'
8
+ ? JSON.stringify(value)
9
+ : (value as string | number | boolean),
10
+ );
11
+ return `${encodedKey}=${encodedValue}`;
12
+ })
13
+ .filter((entry) => !!entry)
14
+ .join('&');
15
+ }