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

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 (64) hide show
  1. package/LICENSE.md +21 -0
  2. package/README.md +281 -231
  3. package/dist/js/notabene.js +1 -0
  4. package/dist/notabene.cjs +1 -1
  5. package/dist/notabene.d.ts +1052 -209
  6. package/dist/notabene.js +275 -105
  7. package/dist/tsdoc-metadata.json +1 -1
  8. package/package.json +36 -26
  9. package/src/__tests__/notabene.test.ts +43 -0
  10. package/src/components/EmbeddedComponent.ts +141 -22
  11. package/src/components/__tests__/EmbeddedComponent.test.ts +73 -20
  12. package/src/ivms/types.ts +230 -152
  13. package/src/locales.ts +47 -0
  14. package/src/notabene.ts +243 -90
  15. package/src/types.ts +723 -144
  16. package/src/utils/MessageEventManager.ts +70 -12
  17. package/src/utils/__tests__/MessageEventManager.test.ts +13 -5
  18. package/src/utils/arbitraries.ts +9 -4
  19. package/.editorconfig +0 -10
  20. package/.gitlab-ci.yml +0 -85
  21. package/.husky/commit-msg +0 -4
  22. package/.husky/pre-commit +0 -4
  23. package/.husky/pre-push +0 -4
  24. package/.prettierrc +0 -4
  25. package/.releaserc.json +0 -16
  26. package/.vscode/extensions.json +0 -3
  27. package/.vscode/settings.json +0 -11
  28. package/.yarn/releases/yarn-berry.cjs +0 -925
  29. package/.yarnrc.yml +0 -3
  30. package/CODEOWNERS +0 -1
  31. package/api-extractor.json +0 -434
  32. package/eslint.config.js +0 -24
  33. package/etc/javascript-sdk.api.md +0 -363
  34. package/index.html +0 -137
  35. package/temp/javascript-sdk.api.json +0 -3509
  36. package/temp/javascript-sdk.api.md +0 -363
  37. package/ts-out/src/__tests__/notabene.test.d.ts +0 -1
  38. package/ts-out/src/__tests__/notabene.test.js +0 -88
  39. package/ts-out/src/arbitraries.d.ts +0 -4
  40. package/ts-out/src/arbitraries.js +0 -8
  41. package/ts-out/src/components/EmbeddedComponent.d.ts +0 -25
  42. package/ts-out/src/components/EmbeddedComponent.js +0 -87
  43. package/ts-out/src/components/__tests__/EmbeddedComponent.test.d.ts +0 -1
  44. package/ts-out/src/components/__tests__/EmbeddedComponent.test.js +0 -132
  45. package/ts-out/src/ivms/types.d.ts +0 -252
  46. package/ts-out/src/ivms/types.js +0 -1
  47. package/ts-out/src/notabene.d.ts +0 -35
  48. package/ts-out/src/notabene.js +0 -59
  49. package/ts-out/src/types.d.ts +0 -357
  50. package/ts-out/src/types.js +0 -85
  51. package/ts-out/src/utils/MessageEventManager.d.ts +0 -12
  52. package/ts-out/src/utils/MessageEventManager.js +0 -45
  53. package/ts-out/src/utils/__tests__/MessageEventManager.test.d.ts +0 -1
  54. package/ts-out/src/utils/__tests__/MessageEventManager.test.js +0 -73
  55. package/ts-out/src/utils/arbitraries.d.ts +0 -6
  56. package/ts-out/src/utils/arbitraries.js +0 -7
  57. package/ts-out/src/utils/caip.d.ts +0 -13
  58. package/ts-out/src/utils/caip.js +0 -15
  59. package/ts-out/src/utils/urls.d.ts +0 -1
  60. package/ts-out/src/utils/urls.js +0 -14
  61. package/ts-out/tsconfig.tsbuildinfo +0 -1
  62. package/tsconfig.json +0 -22
  63. package/tsconfig.tsbuildinfo +0 -1
  64. package/vite.config.js +0 -13
@@ -2,7 +2,6 @@ import {
2
2
  CMType,
3
3
  HMType,
4
4
  HostMessage,
5
- Transaction,
6
5
  TransactionResponse,
7
6
  ValidationError,
8
7
  } from '../types';
@@ -15,23 +14,32 @@ import {
15
14
  * An embedded Notabene component
16
15
  * @public
17
16
  */
18
- export default class EmbeddedComponent {
17
+
18
+ export default class EmbeddedComponent<V, O> {
19
19
  private _url: string;
20
- private _value: Partial<Transaction>;
20
+ private _value: Partial<V>;
21
+ private _options?: O;
21
22
  private _errors: ValidationError[] = [];
22
23
 
23
24
  private iframe?: HTMLIFrameElement;
24
- private eventManager: MessageEventManager;
25
- private ready = false;
25
+ private eventManager: MessageEventManager<V, O>;
26
+ private modal?: HTMLDialogElement;
27
+
28
+ /**
29
+ * Creates an instance of EmbeddedComponent.
30
+ * @param url - The URL of the embedded component
31
+ * @param value - The initial transaction value
32
+ */
26
33
 
27
- constructor(url: string, value: Partial<Transaction>) {
34
+ constructor(url: string, value: Partial<V>, options?: O) {
28
35
  this._url = url;
29
36
  this._value = value;
30
- this.eventManager = new MessageEventManager();
37
+ this._options = options;
38
+ this.eventManager = new MessageEventManager<V, O>();
31
39
  this.on(CMType.INVALID, (message) => {
32
40
  if (message.type === CMType.INVALID) {
33
41
  this._errors = message.errors;
34
- this._value = message.value as Transaction;
42
+ this._value = message.value as V;
35
43
  }
36
44
  });
37
45
  this.on(CMType.RESIZE, (message) => {
@@ -40,64 +48,128 @@ export default class EmbeddedComponent {
40
48
  }
41
49
  });
42
50
  }
51
+ /**
52
+ * Gets the URL of the embedded component
53
+ * @returns The URL of the embedded component
54
+ */
43
55
 
44
56
  public get url(): string {
45
57
  return this._url;
46
58
  }
59
+ /**
60
+ * Gets the current transaction value
61
+ * @returns The current transaction value
62
+ */
47
63
 
48
- public get value(): Partial<Transaction> {
64
+ public get value(): Partial<V> {
49
65
  return this._value;
50
66
  }
51
67
 
68
+ public get options(): O | undefined {
69
+ return this._options;
70
+ }
71
+
52
72
  public get errors(): ValidationError[] {
53
73
  return this._errors;
54
74
  }
55
75
 
76
+ /**
77
+ * Opens the component URL in the current window
78
+ */
79
+
56
80
  public open() {
57
81
  document.location.href = this.url;
58
82
  }
59
83
 
84
+ /**
85
+ * Mounts the component to a parent element
86
+ * @param parentId - The ID of the parent element
87
+ * @throws Will throw an error if the parent element is not found
88
+ */
89
+
60
90
  mount(parentId: string) {
91
+ const parent = document.querySelector(parentId);
92
+ if (!parent) throw new Error(`parentID ${parentId} not found`);
93
+ this.embed(parent);
94
+ }
95
+
96
+ /**
97
+ * Embeds the component into a parent element
98
+ * @param parent - The parent element to embed the component into
99
+ */
100
+ embed(parent: Element, modal: boolean = false) {
101
+ // console.log(this.url);
102
+ this.removeEmbed();
61
103
  this.iframe = document.createElement('iframe');
62
- this.iframe.src = this.url;
104
+ this.iframe.src = this.url + (!modal ? '&embedded=true' : '');
105
+ this.iframe.allow = 'web-share';
63
106
  this.iframe.style.width = '100%';
64
107
  this.iframe.style.height = '100px';
65
108
  this.iframe.style.border = 'none';
66
109
  this.iframe.style.overflow = 'hidden';
110
+ // this.iframe.setAttribute('allowtransparency', 'true');
111
+ // this.iframe.style.backgroundColor = 'transparent';
112
+ parent.appendChild(this.iframe);
67
113
 
68
- window.addEventListener('message', (event) => {
114
+ window.addEventListener('message', (event: MessageEvent) => {
69
115
  if (event.source !== this.iframe?.contentWindow) {
70
116
  return;
71
117
  }
72
- console.log('received message from iframe', event.data);
118
+ // console.log('received message from iframe', event.data);
73
119
  this.eventManager?.setPort(event.ports[0]);
74
- this.ready = true;
75
120
  });
76
121
 
77
- const parent = document.querySelector(parentId);
78
- if (!parent) throw new Error(`parentID ${parentId} not found`);
79
- parent.appendChild(this.iframe);
80
122
  this.iframe?.contentWindow?.focus();
81
123
  }
82
124
 
83
- send(message: HostMessage): void {
125
+ removeEmbed() {
126
+ if (this.iframe) this.iframe.remove();
127
+ }
128
+
129
+ /**
130
+ * Sends a message to the embedded component
131
+ * @param message - The message to send
132
+ */
133
+ send(message: HostMessage<V, O>): void {
84
134
  this.eventManager.send(message);
85
135
  }
86
136
 
87
- on(messageType: string, callback: MessageCallback): void {
137
+ /**
138
+ * Adds an event listener for a specific message type
139
+ * @param messageType - The type of message to listen for
140
+ * @param callback - The callback function to execute when the message is received
141
+ */
142
+
143
+ on(messageType: string, callback: MessageCallback<V>): void {
88
144
  this.eventManager.on(messageType, callback);
89
145
  }
90
146
 
91
- off(messageType: string, callback: MessageCallback): void {
147
+ /**
148
+ * Removes an event listener for a specific message type
149
+ * @param messageType - The type of message to stop listening for
150
+ * @param callback - The callback function to remove
151
+ */
152
+
153
+ off(messageType: string, callback: MessageCallback<V>): void {
92
154
  this.eventManager.off(messageType, callback);
93
155
  }
94
156
 
95
- update(value: Partial<Transaction>) {
157
+ /**
158
+ * Updates the transaction value and sends an update message to the component
159
+ * @param value - The new transaction value
160
+ */
161
+ update(value: Partial<V>, options?: O) {
96
162
  this._value = value;
97
- this.send({ type: HMType.UPDATE, value });
163
+ if (options) this._options = options;
164
+ this.send({ type: HMType.UPDATE, value, options: this._options });
98
165
  }
99
166
 
100
- completion(): Promise<TransactionResponse> {
167
+ /**
168
+ * Waits for the component to complete and returns the transaction response
169
+ * @returns A promise that resolves with the transaction response
170
+ */
171
+
172
+ completion(): Promise<TransactionResponse<V>> {
101
173
  return new Promise((resolve, reject) => {
102
174
  this.on(CMType.COMPLETE, (message) => {
103
175
  resolve((message as any).response);
@@ -107,4 +179,51 @@ export default class EmbeddedComponent {
107
179
  });
108
180
  });
109
181
  }
182
+
183
+ /**
184
+ * Opens the component in a modal dialog
185
+ */
186
+
187
+ openModal(): Promise<TransactionResponse<V>> {
188
+ if (this.modal) {
189
+ this.closeModal();
190
+ }
191
+ this.modal = document.createElement('dialog');
192
+ this.modal.style.border = 'none';
193
+ this.modal.style.backgroundColor = 'white';
194
+ this.modal.style.maxWidth = '100vw';
195
+ this.modal.style.maxHeight = '100vh';
196
+ this.modal.style.width = '600px';
197
+ this.modal.style.height = '600px';
198
+
199
+ document.body.appendChild(this.modal);
200
+ this.embed(this.modal, true);
201
+ this.on(CMType.CANCEL, () => {
202
+ this.closeModal();
203
+ });
204
+
205
+ this.on(CMType.COMPLETE, () => {
206
+ this.closeModal();
207
+ });
208
+
209
+ this.modal.showModal();
210
+ this.modal.addEventListener('click', () => {
211
+ // console.log('click');
212
+ this.closeModal();
213
+ });
214
+ return this.completion();
215
+ }
216
+ /**
217
+ * Closes the modal dialog
218
+ *
219
+ */
220
+
221
+ closeModal(): void {
222
+ if (this.modal) {
223
+ // console.log('closeModal');
224
+ this.modal?.close();
225
+ this.modal.remove();
226
+ this.modal = undefined;
227
+ }
228
+ }
110
229
  }
@@ -1,5 +1,13 @@
1
1
  import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest';
2
- import { CMType, HMType, HostMessage, Transaction } from '../../types';
2
+ import {
3
+ AgentType,
4
+ CMType,
5
+ HMType,
6
+ type HostMessage,
7
+ type Transaction,
8
+ type TransactionOptions,
9
+ type Withdrawal,
10
+ } from '../../types';
3
11
  import EmbeddedComponent from '../EmbeddedComponent';
4
12
 
5
13
  const url = 'https://example.com';
@@ -8,9 +16,11 @@ const value: Partial<Transaction> = { amountDecimal: 100 };
8
16
 
9
17
  describe('EmbeddedComponent', () => {
10
18
  describe('creation', () => {
11
- let component: EmbeddedComponent;
19
+ let component: EmbeddedComponent<Withdrawal, TransactionOptions>;
12
20
  beforeEach(() => {
13
- component = new EmbeddedComponent(url, { amountDecimal: 100 });
21
+ component = new EmbeddedComponent<Withdrawal, TransactionOptions>(url, {
22
+ amountDecimal: 100,
23
+ });
14
24
  });
15
25
 
16
26
  test('sets value', () => {
@@ -60,14 +70,20 @@ describe('EmbeddedComponent', () => {
60
70
  });
61
71
 
62
72
  test('mount', () => {
63
- const component = new EmbeddedComponent(url, value);
73
+ const component = new EmbeddedComponent<Withdrawal, TransactionOptions>(
74
+ url,
75
+ value,
76
+ );
64
77
  component.mount(parentId);
65
- expect(iframe?.src).toBe(url);
78
+ expect(iframe?.src).toBe(url + '&embedded=true');
66
79
  expect(parentElement.appendChild).toHaveBeenCalledWith(iframe);
67
80
  });
68
81
 
69
82
  test('on', () => {
70
- const component = new EmbeddedComponent(url, value);
83
+ const component = new EmbeddedComponent<Withdrawal, TransactionOptions>(
84
+ url,
85
+ value,
86
+ );
71
87
  const messageType = 'customEvent';
72
88
  const callback = vi.fn();
73
89
  component.on(messageType, callback);
@@ -78,7 +94,10 @@ describe('EmbeddedComponent', () => {
78
94
  });
79
95
 
80
96
  test('off', () => {
81
- const component = new EmbeddedComponent(url, value);
97
+ const component = new EmbeddedComponent<Withdrawal, TransactionOptions>(
98
+ url,
99
+ value,
100
+ );
82
101
  const messageType = 'customEvent';
83
102
  const callback = vi.fn();
84
103
  component.on(messageType, callback);
@@ -96,7 +115,8 @@ describe('EmbeddedComponent', () => {
96
115
  let messageHandler: (event: MessageEvent) => void;
97
116
  let port: MessagePort;
98
117
  let handshake: MessageEvent;
99
- let component: EmbeddedComponent;
118
+ let component: EmbeddedComponent<Withdrawal, TransactionOptions>;
119
+ let options: TransactionOptions;
100
120
 
101
121
  beforeEach(() => {
102
122
  port = {
@@ -113,7 +133,12 @@ describe('EmbeddedComponent', () => {
113
133
  .mockImplementation((event, handler) => {
114
134
  messageHandler = handler;
115
135
  });
116
- component = new EmbeddedComponent(url, value);
136
+ options = { allowedAgentTypes: [AgentType.PRIVATE, AgentType.VASP] };
137
+ component = new EmbeddedComponent<Withdrawal, TransactionOptions>(
138
+ url,
139
+ value,
140
+ options,
141
+ );
117
142
  component.mount(parentId);
118
143
 
119
144
  expect(messageHandler).toBeDefined();
@@ -121,23 +146,51 @@ describe('EmbeddedComponent', () => {
121
146
  });
122
147
 
123
148
  test('send', () => {
124
- const message: HostMessage = {
149
+ const message: HostMessage<Withdrawal, TransactionOptions> = {
125
150
  type: HMType.UPDATE,
126
- value: { amountDecimal: 100 },
151
+ value: {
152
+ requestId: 'id',
153
+ },
154
+ options: { allowedAgentTypes: [AgentType.PRIVATE] },
127
155
  };
128
156
  component.send(message);
129
-
130
- // Assert that the message is sent to the embedded component
131
- // and handled correctly.
157
+ expect(port.postMessage).toHaveBeenCalledWith(message);
132
158
  });
133
159
 
134
- test('update', () => {
135
- const newValue: Partial<Transaction> = { amountDecimal: 200 };
136
- component.update(newValue);
160
+ describe('update', () => {
161
+ test('with out options', () => {
162
+ const newValue: Partial<Transaction> = { amountDecimal: 200 };
137
163
 
138
- expect(component.value).toBe(newValue);
139
- });
164
+ const message: HostMessage<Withdrawal, TransactionOptions> = {
165
+ type: HMType.UPDATE,
166
+ value: newValue,
167
+ options,
168
+ };
169
+
170
+ component.update(newValue);
171
+
172
+ expect(component.value).toBe(newValue);
173
+ expect(component.options).toBe(options);
174
+ expect(port.postMessage).toHaveBeenCalledWith(message);
175
+ });
140
176
 
177
+ test('with options', () => {
178
+ const newValue: Partial<Transaction> = { amountDecimal: 200 };
179
+ const newOptions = { allowedAgentTypes: [AgentType.PRIVATE] };
180
+
181
+ const message: HostMessage<Withdrawal, TransactionOptions> = {
182
+ type: HMType.UPDATE,
183
+ value: newValue,
184
+ options: newOptions,
185
+ };
186
+
187
+ component.update(newValue, newOptions);
188
+
189
+ expect(component.value).toBe(newValue);
190
+ expect(component.options).toBe(newOptions);
191
+ expect(port.postMessage).toHaveBeenCalledWith(message);
192
+ });
193
+ });
141
194
  // TODO not sure this actually does what I want it to do
142
195
  test('completion', async () => {
143
196
  const response = { valid: true, value: 'completed' };
@@ -147,7 +200,7 @@ describe('EmbeddedComponent', () => {
147
200
  // @ts-expect-error - we've already verified that port exists
148
201
  port.onmessage({
149
202
  data: { type: CMType.COMPLETE, response },
150
- } as MessageEvent);
203
+ });
151
204
 
152
205
  promise.then((result) => {
153
206
  expect(result).toBe(response);