@uphold/enterprise-widget-sdk-core 0.2.0

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,5 @@
1
+ /**
2
+ * Exports.
3
+ */
4
+ export declare const logSymbol: unique symbol;
5
+ //# sourceMappingURL=constants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,eAAO,MAAM,SAAS,eAAgB,CAAC"}
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Exports.
3
+ */
4
+ export const logSymbol = Symbol('log');
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Exports.
3
+ */
4
+ export * from './constants';
5
+ export * from './types';
6
+ export * from './widget';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,aAAa,CAAC;AAC5B,cAAc,SAAS,CAAC;AACxB,cAAc,UAAU,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Exports.
3
+ */
4
+ export * from './constants';
5
+ export * from './types';
6
+ export * from './widget';
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Module dependencies.
3
+ */
4
+ import type { WidgetCancelMessageEventData, WidgetCancelMessageType, WidgetCompleteMessageEventData, WidgetCompleteMessageType, WidgetError, WidgetErrorMessageEventData, WidgetErrorMessageType, WidgetMessageEvent, WidgetReadyMessageType } from '@uphold/enterprise-widget-messaging-types';
5
+ /**
6
+ * External API Types.
7
+ */
8
+ export type { WidgetError, WidgetErrorMessageEventData, WidgetCompleteMessageEventData, WidgetCancelMessageEventData };
9
+ export type WidgetReadyEventType = WidgetReadyMessageType;
10
+ export type WidgetCompleteEventType = WidgetCompleteMessageType;
11
+ export type WidgetCancelEventType = WidgetCancelMessageType;
12
+ export type WidgetErrorEventType = WidgetErrorMessageType;
13
+ export type WidgetReadyEventDetail = {
14
+ type: WidgetReadyEventType;
15
+ };
16
+ export type WidgetCompleteEventDetail = {
17
+ type: WidgetCompleteEventType;
18
+ };
19
+ export type WidgetCancelEventDetail = {
20
+ type: WidgetCancelEventType;
21
+ };
22
+ export type WidgetErrorEventDetail = {
23
+ type: WidgetErrorEventType;
24
+ error: string;
25
+ };
26
+ export type ExtractMessageEventDataForType<TMessageEvent extends WidgetMessageEvent, TType extends TMessageEvent['data']['type']> = Extract<TMessageEvent, {
27
+ data: {
28
+ type: TType;
29
+ };
30
+ }>['data'];
31
+ export type WidgetLoadEvent<TMessageEvent extends WidgetMessageEvent> = CustomEvent<ExtractMessageEventDataForType<TMessageEvent, 'load'>>;
32
+ export type WidgetReadyEvent<TMessageEvent extends WidgetMessageEvent> = CustomEvent<ExtractMessageEventDataForType<TMessageEvent, 'ready'>>;
33
+ export type WidgetCompleteEvent<TMessageEvent extends WidgetMessageEvent> = CustomEvent<ExtractMessageEventDataForType<TMessageEvent, 'complete'>>;
34
+ export type WidgetCancelEvent<TMessageEvent extends WidgetMessageEvent> = CustomEvent<ExtractMessageEventDataForType<TMessageEvent, 'cancel'>>;
35
+ export type WidgetErrorEvent<TMessageEvent extends WidgetMessageEvent> = CustomEvent<ExtractMessageEventDataForType<TMessageEvent, 'error'>>;
36
+ export type WidgetEvent<TMessageEvent extends WidgetMessageEvent = WidgetMessageEvent> = WidgetReadyEvent<TMessageEvent> | WidgetCompleteEvent<TMessageEvent> | WidgetCancelEvent<TMessageEvent> | WidgetErrorEvent<TMessageEvent>;
37
+ export type WidgetMountIframeOptions = Record<string, unknown>;
38
+ export type WidgetOptions = {
39
+ debug?: boolean;
40
+ };
41
+ export type PaymentWidgetOptions = WidgetOptions;
42
+ //# sourceMappingURL=base.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../src/types/base.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EACV,4BAA4B,EAC5B,uBAAuB,EACvB,8BAA8B,EAC9B,yBAAyB,EACzB,WAAW,EACX,2BAA2B,EAC3B,sBAAsB,EACtB,kBAAkB,EAClB,sBAAsB,EACvB,MAAM,2CAA2C,CAAC;AAEnD;;GAEG;AAEH,YAAY,EAAE,WAAW,EAAE,2BAA2B,EAAE,8BAA8B,EAAE,4BAA4B,EAAE,CAAC;AAEvH,MAAM,MAAM,oBAAoB,GAAG,sBAAsB,CAAC;AAC1D,MAAM,MAAM,uBAAuB,GAAG,yBAAyB,CAAC;AAChE,MAAM,MAAM,qBAAqB,GAAG,uBAAuB,CAAC;AAC5D,MAAM,MAAM,oBAAoB,GAAG,sBAAsB,CAAC;AAE1D,MAAM,MAAM,sBAAsB,GAAG;IACnC,IAAI,EAAE,oBAAoB,CAAC;CAC5B,CAAC;AAEF,MAAM,MAAM,yBAAyB,GAAG;IACtC,IAAI,EAAE,uBAAuB,CAAC;CAC/B,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG;IACpC,IAAI,EAAE,qBAAqB,CAAC;CAC7B,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG;IACnC,IAAI,EAAE,oBAAoB,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,8BAA8B,CACxC,aAAa,SAAS,kBAAkB,EACxC,KAAK,SAAS,aAAa,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,IACzC,OAAO,CAAC,aAAa,EAAE;IAAE,IAAI,EAAE;QAAE,IAAI,EAAE,KAAK,CAAA;KAAE,CAAA;CAAE,CAAC,CAAC,MAAM,CAAC,CAAC;AAE9D,MAAM,MAAM,eAAe,CAAC,aAAa,SAAS,kBAAkB,IAAI,WAAW,CACjF,8BAA8B,CAAC,aAAa,EAAE,MAAM,CAAC,CACtD,CAAC;AACF,MAAM,MAAM,gBAAgB,CAAC,aAAa,SAAS,kBAAkB,IAAI,WAAW,CAClF,8BAA8B,CAAC,aAAa,EAAE,OAAO,CAAC,CACvD,CAAC;AACF,MAAM,MAAM,mBAAmB,CAAC,aAAa,SAAS,kBAAkB,IAAI,WAAW,CACrF,8BAA8B,CAAC,aAAa,EAAE,UAAU,CAAC,CAC1D,CAAC;AACF,MAAM,MAAM,iBAAiB,CAAC,aAAa,SAAS,kBAAkB,IAAI,WAAW,CACnF,8BAA8B,CAAC,aAAa,EAAE,QAAQ,CAAC,CACxD,CAAC;AACF,MAAM,MAAM,gBAAgB,CAAC,aAAa,SAAS,kBAAkB,IAAI,WAAW,CAClF,8BAA8B,CAAC,aAAa,EAAE,OAAO,CAAC,CACvD,CAAC;AAEF,MAAM,MAAM,WAAW,CAAC,aAAa,SAAS,kBAAkB,GAAG,kBAAkB,IACjF,gBAAgB,CAAC,aAAa,CAAC,GAC/B,mBAAmB,CAAC,aAAa,CAAC,GAClC,iBAAiB,CAAC,aAAa,CAAC,GAChC,gBAAgB,CAAC,aAAa,CAAC,CAAC;AAEpC,MAAM,MAAM,wBAAwB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAE/D,MAAM,MAAM,aAAa,GAAG;IAC1B,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG,aAAa,CAAC"}
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Module dependencies.
3
+ */
4
+ export {};
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Exports.
3
+ */
4
+ export * from './base';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,QAAQ,CAAC"}
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Exports.
3
+ */
4
+ export * from './base';
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Module dependencies.
3
+ */
4
+ import type { WidgetEvent, WidgetMountIframeOptions, WidgetOptions } from './types/base';
5
+ import type { WidgetMessageEvent, WidgetSession } from '@uphold/enterprise-widget-messaging-types';
6
+ import { logSymbol } from './constants';
7
+ /**
8
+ * Widget base class.
9
+ */
10
+ declare class Widget<TSession extends WidgetSession, TMessageEvent extends WidgetMessageEvent, TEvent extends WidgetEvent<TMessageEvent>> extends EventTarget {
11
+ #private;
12
+ session: TSession;
13
+ mountOptions?: WidgetMountIframeOptions;
14
+ options?: WidgetOptions;
15
+ [logSymbol]: {
16
+ log: (message?: any, ...optionalParams: any[]) => void;
17
+ warn: (message?: any, ...optionalParams: any[]) => void;
18
+ };
19
+ constructor(session: TSession, options?: WidgetOptions);
20
+ on<T extends TEvent['detail']['type']>(event: T, listener: (event: Extract<TEvent, {
21
+ detail: {
22
+ type: T;
23
+ };
24
+ }>) => void): void;
25
+ off<T extends TEvent['detail']['type']>(event: T, listener: (event: Extract<TEvent, {
26
+ detail: {
27
+ type: T;
28
+ };
29
+ }>) => void): void;
30
+ mountIframe(element: HTMLElement, mountOptions?: WidgetMountIframeOptions): void;
31
+ unmount(): void;
32
+ }
33
+ /**
34
+ * Exports.
35
+ */
36
+ export { Widget };
37
+ //# sourceMappingURL=widget.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"widget.d.ts","sourceRoot":"","sources":["../src/widget.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,wBAAwB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AACzF,OAAO,KAAK,EAEV,kBAAkB,EAClB,aAAa,EACd,MAAM,2CAA2C,CAAC;AACnD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC;;GAEG;AAEH,cAAM,MAAM,CACV,QAAQ,SAAS,aAAa,EAC9B,aAAa,SAAS,kBAAkB,EACxC,MAAM,SAAS,WAAW,CAAC,aAAa,CAAC,CACzC,SAAQ,WAAW;;IAGnB,OAAO,EAAE,QAAQ,CAAC;IAClB,YAAY,CAAC,EAAE,wBAAwB,CAAC;IACxC,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,CAAC,SAAS,CAAC;wBAEO,GAAG,qBAAqB,GAAG,EAAE;yBAI5B,GAAG,qBAAqB,GAAG,EAAE;MAG9C;gBAEU,OAAO,EAAE,QAAQ,EAAE,OAAO,CAAC,EAAE,aAAa;IAWtD,EAAE,CAAC,CAAC,SAAS,MAAM,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,EACnC,KAAK,EAAE,CAAC,EACR,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,MAAM,EAAE;QAAE,MAAM,EAAE;YAAE,IAAI,EAAE,CAAC,CAAA;SAAE,CAAA;KAAE,CAAC,KAAK,IAAI;IAarE,GAAG,CAAC,CAAC,SAAS,MAAM,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,EACpC,KAAK,EAAE,CAAC,EACR,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,MAAM,EAAE;QAAE,MAAM,EAAE;YAAE,IAAI,EAAE,CAAC,CAAA;SAAE,CAAA;KAAE,CAAC,KAAK,IAAI;IAiBrE,WAAW,CAAC,OAAO,EAAE,WAAW,EAAE,YAAY,CAAC,EAAE,wBAAwB;IA4BzE,OAAO;CAsGR;AAED;;GAEG;AAEH,OAAO,EAAE,MAAM,EAAE,CAAC"}
package/dist/widget.js ADDED
@@ -0,0 +1,151 @@
1
+ /**
2
+ * Module dependencies.
3
+ */
4
+ import { logSymbol } from './constants';
5
+ /**
6
+ * Widget base class.
7
+ */
8
+ class Widget extends EventTarget {
9
+ #iframe;
10
+ #eventListeners = new Map();
11
+ session;
12
+ mountOptions;
13
+ options;
14
+ [logSymbol] = {
15
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
16
+ log: (message, ...optionalParams) => {
17
+ this.#consoleWrapper('log', message, ...optionalParams);
18
+ },
19
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
20
+ warn: (message, ...optionalParams) => {
21
+ this.#consoleWrapper('warn', message, ...optionalParams);
22
+ }
23
+ };
24
+ constructor(session, options) {
25
+ super();
26
+ this.session = session;
27
+ this.options = options;
28
+ if (this.options?.debug) {
29
+ this[logSymbol].log('Debug mode is enabled.');
30
+ }
31
+ }
32
+ on(event, listener) {
33
+ this.addEventListener(event, listener);
34
+ if (!this.#eventListeners.has(event)) {
35
+ this.#eventListeners.set(event, []);
36
+ }
37
+ this.#eventListeners.get(event).push(listener);
38
+ this[logSymbol].log(`Added listener for event: '${event}'.`);
39
+ }
40
+ off(event, listener) {
41
+ this.removeEventListener(event, listener);
42
+ if (this.#eventListeners.has(event)) {
43
+ const listeners = this.#eventListeners.get(event).filter(currentListener => currentListener !== listener);
44
+ if (listeners.length > 0) {
45
+ this.#eventListeners.set(event, listeners);
46
+ }
47
+ else {
48
+ this.#eventListeners.delete(event);
49
+ }
50
+ }
51
+ this[logSymbol].log(`Removed listener for event: '${event}'.`);
52
+ }
53
+ mountIframe(element, mountOptions) {
54
+ this[logSymbol].log('Validating element and initializing iframe mounting.');
55
+ if (!element || !(element instanceof HTMLElement)) {
56
+ throw new TypeError(`Type of 'element' parameter is invalid`);
57
+ }
58
+ this.mountOptions = mountOptions;
59
+ try {
60
+ this[logSymbol].log('Starting widget event listener.');
61
+ this.#startWidgetEventsListener();
62
+ this[logSymbol].log('Creating and appending iframe to the DOM.');
63
+ this.#createIframe(element);
64
+ this[logSymbol].log('Widget successfully mounted.');
65
+ }
66
+ catch (e) {
67
+ this[logSymbol].log('Error occurred while mounting the widget in iframe: ', e);
68
+ this.unmount();
69
+ throw new Error('Unable to mount widget: ', { cause: e });
70
+ }
71
+ }
72
+ unmount() {
73
+ window.removeEventListener('message', this.#widgetEventListener);
74
+ this.#eventListeners.forEach((listeners, event) => {
75
+ listeners.forEach(listener => this.removeEventListener(event, listener));
76
+ });
77
+ this.#eventListeners.clear();
78
+ // Remove the iframe from the DOM
79
+ if (this.#iframe) {
80
+ this.#iframe.remove();
81
+ this.#iframe = undefined;
82
+ }
83
+ }
84
+ #createIframe(element) {
85
+ const iframe = document.createElement('iframe');
86
+ iframe.setAttribute('src', this.session.url);
87
+ iframe.setAttribute('allow', 'clipboard-write *; clipboard-read *');
88
+ iframe.style.width = '100%';
89
+ iframe.style.height = '100%';
90
+ iframe.style.border = 'none';
91
+ element.appendChild(iframe);
92
+ this.#iframe = iframe;
93
+ }
94
+ #emit(event, data) {
95
+ this[logSymbol].log(`'${event}' event raised. Details: `, data);
96
+ this.dispatchEvent(new CustomEvent(event, { detail: data }));
97
+ }
98
+ #sendMessageToWidget(message) {
99
+ this.#iframe?.contentWindow?.postMessage(message, '*');
100
+ }
101
+ #startWidgetEventsListener() {
102
+ window.addEventListener('message', this.#widgetEventListener);
103
+ }
104
+ #widgetEventListener = (event) => {
105
+ const eventOrigin = new URL(event.origin).origin;
106
+ if (eventOrigin !== this.session.url) {
107
+ this[logSymbol].warn(`[Widget -> Host] ⚠️ Discarding message from '${eventOrigin}' as it does not match widget URL '${this.session.url}' ⚠️`);
108
+ return;
109
+ }
110
+ this[logSymbol].log('[Widget -> Host] ', event.data);
111
+ switch (event.data.type) {
112
+ case 'load': {
113
+ const widgetInitMessage = {
114
+ ...this.session,
115
+ type: 'init'
116
+ };
117
+ this.#sendMessageToWidget(widgetInitMessage);
118
+ this[logSymbol].log('[Host -> Widget] ', widgetInitMessage);
119
+ break;
120
+ }
121
+ case 'complete': {
122
+ this.#emit('complete', event.data);
123
+ break;
124
+ }
125
+ case 'cancel': {
126
+ this.#emit('cancel');
127
+ break;
128
+ }
129
+ case 'error': {
130
+ this.#emit('error', event.data);
131
+ break;
132
+ }
133
+ case 'ready': {
134
+ this.#emit('ready');
135
+ break;
136
+ }
137
+ default:
138
+ break;
139
+ }
140
+ };
141
+ #consoleWrapper(prop, ...messages) {
142
+ if (this.options?.debug) {
143
+ // eslint-disable-next-line no-console
144
+ console[prop](`[${this.constructor.name}] `, ...messages);
145
+ }
146
+ }
147
+ }
148
+ /**
149
+ * Exports.
150
+ */
151
+ export { Widget };
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "@uphold/enterprise-widget-sdk-core",
3
+ "version": "0.2.0",
4
+ "type": "module",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "files": [
8
+ "dist"
9
+ ],
10
+ "description": "Enterprise Widget SDK Core",
11
+ "scripts": {
12
+ "build": "rm -rf dist && tsc -b tsconfig.build.json --force",
13
+ "lint": "eslint .",
14
+ "postinstall": "npm run build",
15
+ "release": "npx --yes release-it@^19 --config ../../.release-it.cjs",
16
+ "test": "vitest",
17
+ "typecheck": "tsc --noEmit"
18
+ },
19
+ "repository": {
20
+ "type": "git",
21
+ "url": "https://github.com/uphold/enterprise-widget-sdk",
22
+ "directory": "packages/core"
23
+ },
24
+ "publishConfig": {
25
+ "access": "public"
26
+ },
27
+ "lint-staged": {
28
+ "*.ts*": [
29
+ "eslint"
30
+ ]
31
+ },
32
+ "dependencies": {
33
+ "@uphold/enterprise-widget-messaging-types": "^0.7.0"
34
+ }
35
+ }