@dintero/checkout-web-sdk 0.0.15 → 0.3.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.
Files changed (45) hide show
  1. package/.babelrc +3 -0
  2. package/.github/dependabot.yml +10 -0
  3. package/.github/workflows/build.yml +25 -0
  4. package/.github/workflows/release.yml +34 -0
  5. package/.releaserc.json +11 -0
  6. package/CHANGELOG.md +17 -3
  7. package/LISENCE +20 -0
  8. package/README.md +91 -24
  9. package/coverage/Chrome Headless 80.0.3987.0 (Linux x86_64)/html/base.css +224 -0
  10. package/coverage/Chrome Headless 80.0.3987.0 (Linux x86_64)/html/block-navigation.js +79 -0
  11. package/coverage/Chrome Headless 80.0.3987.0 (Linux x86_64)/html/checkout.ts.html +383 -0
  12. package/coverage/Chrome Headless 80.0.3987.0 (Linux x86_64)/html/createIframeAsync.ts.html +254 -0
  13. package/coverage/Chrome Headless 80.0.3987.0 (Linux x86_64)/html/favicon.png +0 -0
  14. package/coverage/Chrome Headless 80.0.3987.0 (Linux x86_64)/html/index.html +171 -0
  15. package/coverage/Chrome Headless 80.0.3987.0 (Linux x86_64)/html/index.ts.html +1133 -0
  16. package/coverage/Chrome Headless 80.0.3987.0 (Linux x86_64)/html/prettify.css +1 -0
  17. package/coverage/Chrome Headless 80.0.3987.0 (Linux x86_64)/html/prettify.js +2 -0
  18. package/coverage/Chrome Headless 80.0.3987.0 (Linux x86_64)/html/sort-arrow-sprite.png +0 -0
  19. package/coverage/Chrome Headless 80.0.3987.0 (Linux x86_64)/html/sorter.js +170 -0
  20. package/coverage/Chrome Headless 80.0.3987.0 (Linux x86_64)/html/subscribe.ts.html +443 -0
  21. package/coverage/Chrome Headless 80.0.3987.0 (Linux x86_64)/html/url.ts.html +185 -0
  22. package/dist/declarations/package.d.ts +52 -0
  23. package/dist/{src → declarations}/src/checkout.d.ts +20 -2
  24. package/dist/{src → declarations}/src/createIframeAsync.d.ts +0 -0
  25. package/dist/{src/src/dintero-checkout-web-sdk.d.ts → declarations/src/index.d.ts} +6 -2
  26. package/dist/declarations/src/session.d.ts +953 -0
  27. package/dist/{src → declarations}/src/subscribe.d.ts +10 -2
  28. package/dist/{src → declarations}/src/url.d.ts +1 -0
  29. package/dist/dintero-checkout-web-sdk.cjs.d.ts +1 -0
  30. package/dist/dintero-checkout-web-sdk.cjs.dev.js +475 -0
  31. package/dist/dintero-checkout-web-sdk.cjs.js +7 -0
  32. package/dist/dintero-checkout-web-sdk.cjs.prod.js +475 -0
  33. package/dist/dintero-checkout-web-sdk.esm.js +470 -0
  34. package/dist/dintero-checkout-web-sdk.umd.min.js +7 -0
  35. package/dist/dintero-checkout-web-sdk.umd.min.js.map +1 -0
  36. package/karma.conf.js +33 -0
  37. package/package.json +49 -43
  38. package/dist/checkout-web-sdk.js +0 -2
  39. package/dist/checkout-web-sdk.js.map +0 -1
  40. package/dist/checkout-web-sdk.js.mjs +0 -2
  41. package/dist/checkout-web-sdk.js.mjs.map +0 -1
  42. package/dist/checkout-web-sdk.modern.js +0 -2
  43. package/dist/checkout-web-sdk.modern.js.map +0 -1
  44. package/dist/checkout-web-sdk.umd.js +0 -2
  45. package/dist/checkout-web-sdk.umd.js.map +0 -1
@@ -1,5 +1,5 @@
1
- import { CheckoutEvents, InternalCheckoutEvents, SessionEvent } from "./checkout";
2
- import { DinteroCheckoutInstance } from "./dintero-checkout-web-sdk";
1
+ import { CheckoutEvents, InternalCheckoutEvents, SessionEvent, SessionValidationCallback } from "./checkout";
2
+ import { DinteroCheckoutInstance } from ".";
3
3
  /**
4
4
  * Unsubscribe handler from event(s).
5
5
  */
@@ -21,10 +21,18 @@ export declare type Subscription = {
21
21
  * Post a SessionLock-event to the checkout iframe.
22
22
  */
23
23
  export declare const postSessionLock: (iframe: HTMLIFrameElement, sid: string) => void;
24
+ /**
25
+ * Post the validation result to the checkout iframe
26
+ */
27
+ export declare const postValidationResult: (iframe: HTMLIFrameElement, sid: string, result: SessionValidationCallback) => void;
24
28
  /**
25
29
  * Post RefreshSession-event to the checkout iframe.
26
30
  */
27
31
  export declare const postSessionRefresh: (iframe: HTMLIFrameElement, sid: string) => void;
32
+ /**
33
+ * Post setActivePaymentProductType-event to the checkout iframe.
34
+ */
35
+ export declare const postActivePaymentProductType: (iframe: HTMLIFrameElement, sid: string, paymentProductType?: string) => void;
28
36
  /**
29
37
  * Subscribe to events from an iframe given a handler and a set
30
38
  * of event types.
@@ -11,5 +11,6 @@ export interface SessionUrlOptions {
11
11
  endpoint: string;
12
12
  language: string | undefined;
13
13
  ui?: "fullscreen" | "inline";
14
+ shouldCallValidateSession: boolean;
14
15
  }
15
16
  export declare const getSessionUrl: (options: SessionUrlOptions) => string;
@@ -0,0 +1 @@
1
+ export * from "./declarations/src/index";
@@ -0,0 +1,475 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ require('native-promise-only');
6
+
7
+ var pkg = {
8
+ name: "@dintero/checkout-web-sdk",
9
+ version: "0.0.0-development",
10
+ description: "Dintero Checkout SDK for web frontends",
11
+ main: "dist/dintero-checkout-web-sdk.cjs.js",
12
+ module: "dist/dintero-checkout-web-sdk.esm.js",
13
+ "umd:main": "dist/dintero-checkout-web-sdk.umd.min.js",
14
+ unpkg: "dist/dintero-checkout-web-sdk.umd.min.js",
15
+ types: "dist/dintero-checkout-web-sdk.cjs.d.ts",
16
+ preconstruct: {
17
+ umdName: "dintero"
18
+ },
19
+ scripts: {
20
+ build: "preconstruct build",
21
+ test: "karma start",
22
+ "semantic-release": "semantic-release"
23
+ },
24
+ "private": false,
25
+ repository: {
26
+ type: "git",
27
+ url: "https://github.com/Dintero/Dintero.Checkout.Web.SDK.git"
28
+ },
29
+ homepage: "https://github.com/Dintero/Dintero.Checkout.Web.SDK#readme",
30
+ author: "Sven Nicolai Viig <sven@dintero.com> (http://dintero.com)",
31
+ license: "MIT",
32
+ bugs: {
33
+ url: "https://github.com/Dintero/Dintero.Checkout.Web.SDK/issues"
34
+ },
35
+ devDependencies: {
36
+ "@babel/preset-env": "^7.14.1",
37
+ "@babel/preset-typescript": "^7.13.0",
38
+ "@preconstruct/cli": "^2.1.0",
39
+ "@semantic-release/git": "^10.0.1",
40
+ chai: "^4.2.0",
41
+ karma: "^6.3.14",
42
+ "karma-chai": "^0.1.0",
43
+ "karma-chrome-launcher": "^3.1.0",
44
+ "karma-mocha": "^2.0.1",
45
+ "karma-typescript": "^5.0.3",
46
+ mocha: "^8.1.1",
47
+ prettier: "^1.19.1",
48
+ puppeteer: "^2.1.0",
49
+ rollup: "^1.30.1",
50
+ "semantic-release": "^19.0.2",
51
+ sinon: "^8.1.1",
52
+ typescript: "^4.2.4"
53
+ },
54
+ dependencies: {
55
+ "native-promise-only": "^0.8.1"
56
+ }
57
+ };
58
+
59
+ let CheckoutEvents;
60
+
61
+ (function (CheckoutEvents) {
62
+ CheckoutEvents["SessionNotFound"] = "SessionNotFound";
63
+ CheckoutEvents["SessionLoaded"] = "SessionLoaded";
64
+ CheckoutEvents["SessionUpdated"] = "SessionUpdated";
65
+ CheckoutEvents["SessionCancel"] = "SessionCancel";
66
+ CheckoutEvents["SessionPaymentOnHold"] = "SessionPaymentOnHold";
67
+ CheckoutEvents["SessionPaymentAuthorized"] = "SessionPaymentAuthorized";
68
+ CheckoutEvents["SessionPaymentError"] = "SessionPaymentError";
69
+ CheckoutEvents["SessionLocked"] = "SessionLocked";
70
+ CheckoutEvents["SessionLockFailed"] = "SessionLockFailed";
71
+ CheckoutEvents["ActivePaymentProductType"] = "ActivePaymentProductType";
72
+ CheckoutEvents["ValidateSession"] = "ValidateSession";
73
+ })(CheckoutEvents || (CheckoutEvents = {}));
74
+
75
+ let InternalCheckoutEvents;
76
+
77
+ (function (InternalCheckoutEvents) {
78
+ InternalCheckoutEvents["HeightChanged"] = "HeightChanged";
79
+ InternalCheckoutEvents["LanguageChanged"] = "LanguageChanged";
80
+ })(InternalCheckoutEvents || (InternalCheckoutEvents = {}));
81
+
82
+ /**
83
+ * Wraps window.location.assign()
84
+ */
85
+
86
+ const windowLocationAssign = url => {
87
+ window.location.assign(url);
88
+ };
89
+ /**
90
+ * Get the url for the session./yarn-error.log
91
+ .DS_Store
92
+ */
93
+
94
+ const getSessionUrl = options => {
95
+ const {
96
+ sid,
97
+ endpoint,
98
+ language,
99
+ ui,
100
+ shouldCallValidateSession
101
+ } = options;
102
+
103
+ if (!endpoint) {
104
+ throw new Error("Invalid endpoint");
105
+ } // Compose url for view session endpoint with optional language parameter.
106
+
107
+
108
+ let languageParam = language ? `language=${language}` : "";
109
+ let uiParam = ui ? `ui=${ui}` : "";
110
+ let sdk = `sdk=${pkg.version}`;
111
+ let validate = shouldCallValidateSession ? `client_side_validation=true` : undefined;
112
+ const params = [languageParam, uiParam, sdk, validate].filter(x => x).join("&");
113
+ return `${endpoint}/v1/view/${sid}${params ? "?" + params : ""}`;
114
+ };
115
+
116
+ /**
117
+ * Creates an iframe and adds it to the container.
118
+ *
119
+ * Returns a promise that resolves to the iframe when the iframe has loaded.
120
+ * Rejects the promise if there is a problem loading the iframe.
121
+ */
122
+ const createIframeAsync = (container, endpoint, url) => {
123
+ if (!container || !container.appendChild) {
124
+ throw new Error("Invalid container");
125
+ }
126
+
127
+ const iframe = document.createElement("iframe"); // No border, transparent and stretch to 100% of the container width.
128
+
129
+ iframe.setAttribute("frameborder", "0");
130
+ iframe.setAttribute("allowTransparency", "true");
131
+ iframe.setAttribute("style", "width:100%; height:0;"); // TODO: Get this to work as expected, might be tricky with current
132
+ // tests since they will require the csp to be "unsafe-inline".
133
+ // The server needs to add the same property in the Content Security
134
+ // Policy headers in the response for this to work. A CSP header set by
135
+ // a meta tag in the iframe target will not be detected as a valid
136
+ // CSP from the iframe host.
137
+ // Content Security Policy, should be limited to "endpoint".
138
+ // iframe.setAttribute("csp", `default-src ${endpoint}`);
139
+ // Apply extra restrictions to the content in the iframe.
140
+ // allow popups is needed to open terms in new window
141
+
142
+ iframe.setAttribute("sandbox", "allow-scripts allow-forms allow-same-origin allow-popups"); // The download priority of the resource in the <iframe>'s src attribute.
143
+
144
+ iframe.setAttribute("importance", "high"); // Set the iframe source to the url.
145
+
146
+ iframe.setAttribute("src", url); // Resolve or reject promise when iframe loads.
147
+ // // Add iframe to the container.
148
+ // container.appendChild(iframe);
149
+
150
+ return {
151
+ iframe,
152
+ initiate: async () => {
153
+ return new Promise((resolve, reject) => {
154
+ iframe.onload = () => resolve();
155
+
156
+ iframe.onerror = () => reject();
157
+
158
+ container.appendChild(iframe);
159
+ });
160
+ }
161
+ };
162
+ };
163
+
164
+ /**
165
+ * Unsubscribe handler from event(s).
166
+ */
167
+
168
+ /**
169
+ * Post a message acknowledgement to the checkout iframe.
170
+ */
171
+ const postAck = (iframe, event) => {
172
+ if (event.data.mid && iframe.contentWindow) {
173
+ iframe.contentWindow.postMessage({
174
+ ack: event.data.mid
175
+ }, event.origin || "*");
176
+ }
177
+ };
178
+ /**
179
+ * Post a SessionLock-event to the checkout iframe.
180
+ */
181
+
182
+
183
+ const postSessionLock = (iframe, sid) => {
184
+ if (iframe.contentWindow) {
185
+ iframe.contentWindow.postMessage({
186
+ type: "LockSession",
187
+ sid
188
+ }, "*");
189
+ }
190
+ };
191
+ /**
192
+ * Post the validation result to the checkout iframe
193
+ */
194
+
195
+ const postValidationResult = (iframe, sid, result) => {
196
+ if (iframe.contentWindow) {
197
+ iframe.contentWindow.postMessage({
198
+ type: "ValidationResult",
199
+ sid,
200
+ ...result
201
+ }, "*");
202
+ }
203
+ };
204
+ /**
205
+ * Post RefreshSession-event to the checkout iframe.
206
+ */
207
+
208
+ const postSessionRefresh = (iframe, sid) => {
209
+ if (iframe.contentWindow) {
210
+ iframe.contentWindow.postMessage({
211
+ type: "RefreshSession",
212
+ sid
213
+ }, "*");
214
+ }
215
+ };
216
+ /**
217
+ * Post setActivePaymentProductType-event to the checkout iframe.
218
+ */
219
+
220
+ const postActivePaymentProductType = (iframe, sid, paymentProductType) => {
221
+ if (iframe.contentWindow) {
222
+ iframe.contentWindow.postMessage({
223
+ type: "SetActivePaymentProductType",
224
+ sid,
225
+ payment_product_type: paymentProductType
226
+ }, "*");
227
+ }
228
+ };
229
+ /**
230
+ * Subscribe to events from an iframe given a handler and a set
231
+ * of event types.
232
+ */
233
+
234
+ const subscribe = options => {
235
+ const {
236
+ sid,
237
+ endpoint,
238
+ handler,
239
+ eventTypes,
240
+ checkout
241
+ } = options; // Wrap event handler in a function that checks for correct origin and
242
+ // filters on event type(s) in the event data.
243
+
244
+ const wrappedHandler = event => {
245
+ const correctOrigin = event.origin === endpoint;
246
+ const correctWindow = event.source === checkout.iframe.contentWindow;
247
+ const correctSid = event.data && event.data.sid === sid;
248
+ const correctMessageType = eventTypes.indexOf(event.data && event.data.type) !== -1;
249
+
250
+ if (correctOrigin && correctWindow && correctSid && correctMessageType) {
251
+ postAck(checkout.iframe, event);
252
+ handler(event.data, checkout);
253
+ }
254
+ }; // Add event listener to the iframe.
255
+
256
+
257
+ window.addEventListener("message", wrappedHandler, false); // Function to remove the event listener from the iframe.
258
+
259
+ const unsubscribe = () => {
260
+ window.removeEventListener("message", wrappedHandler, false);
261
+ }; // Return object with unsubscribe function.
262
+
263
+
264
+ return {
265
+ unsubscribe
266
+ };
267
+ };
268
+
269
+ /**
270
+ * An event handler that navigates to the href in the event.
271
+ */
272
+ const followHref = event => {
273
+ if (event.href) {
274
+ windowLocationAssign(event.href);
275
+ }
276
+ };
277
+ /**
278
+ * An event handler that sets height of the iframe.
279
+ */
280
+
281
+
282
+ const setIframeHeight = (event, checkout) => {
283
+ if (event.height || event.height === 0) {
284
+ checkout.iframe.setAttribute("style", `width:100%; height:${event.height}px;`);
285
+ }
286
+ };
287
+
288
+ const setLanguage = (event, checkout) => {
289
+ if (event.language) {
290
+ checkout.language = event.language;
291
+ }
292
+ };
293
+
294
+ const handleWithResult = (sid, endpoint, handler) => {
295
+ return (event, checkout) => {
296
+ const eventKeys = ["sid", "merchant_reference", "transaction_id", "error"];
297
+ const pairs = eventKeys.map(key => [key, event[key]]);
298
+
299
+ if (event.type === CheckoutEvents.SessionCancel && !event.error) {
300
+ pairs.push(["error", "cancelled"]);
301
+ }
302
+
303
+ pairs.push(["language", checkout.language]);
304
+ pairs.push(["sdk", pkg.version]);
305
+ const urlQuery = pairs.filter(([key, value]) => value).map(([key, value]) => `${key}=${value}`).join("&");
306
+ checkout.iframe.setAttribute("src", `${endpoint}/embedResult/?${urlQuery}`);
307
+ handler(event, checkout);
308
+ };
309
+ };
310
+ /**
311
+ * Show a dintero payment session in an embedded iframe.
312
+ */
313
+
314
+
315
+ const embed = async options => {
316
+ const {
317
+ container,
318
+ sid,
319
+ language,
320
+ endpoint = "https://checkout.dintero.com",
321
+ onSession,
322
+ onSessionCancel,
323
+ onPayment,
324
+ onPaymentAuthorized,
325
+ onPaymentError,
326
+ onSessionNotFound,
327
+ onSessionLocked,
328
+ onSessionLockFailed,
329
+ onActivePaymentType,
330
+ onValidateSession
331
+ } = options;
332
+ const subscriptions = []; // Create iframe
333
+
334
+ const {
335
+ iframe,
336
+ initiate
337
+ } = createIframeAsync(container, endpoint, getSessionUrl({
338
+ sid,
339
+ endpoint,
340
+ language,
341
+ ui: "inline",
342
+ shouldCallValidateSession: onValidateSession !== undefined
343
+ }));
344
+ /**
345
+ * Function that removes the iframe and all event listeners.
346
+ */
347
+
348
+ const destroy = () => {
349
+ if (iframe) {
350
+ subscriptions.forEach(sub => sub.unsubscribe());
351
+
352
+ if (iframe.parentElement) {
353
+ container.removeChild(iframe);
354
+ }
355
+ }
356
+ };
357
+
358
+ const lockSession = () => {
359
+ postSessionLock(iframe, sid);
360
+ };
361
+
362
+ const refreshSession = () => {
363
+ postSessionRefresh(iframe, sid);
364
+ };
365
+
366
+ const setActivePaymentProductType = paymentProductType => {
367
+ postActivePaymentProductType(iframe, sid, paymentProductType);
368
+ };
369
+
370
+ const submitValidationResult = result => {
371
+ postValidationResult(iframe, sid, result);
372
+ };
373
+
374
+ const wrappedOnValidateSession = (event, checkout) => {
375
+ if (onValidateSession) {
376
+ onValidateSession(event, checkout, submitValidationResult);
377
+ }
378
+ };
379
+
380
+ const wrappedOnSessionLocked = (event, checkout) => {
381
+ if (onSessionLocked) {
382
+ onSessionLocked(event, checkout, refreshSession);
383
+ }
384
+ }; // Create checkout object that wraps the destroy function.
385
+
386
+
387
+ const checkout = {
388
+ destroy,
389
+ iframe,
390
+ language,
391
+ lockSession,
392
+ refreshSession,
393
+ setActivePaymentProductType,
394
+ submitValidationResult
395
+ }; // Add event handlers (or in some cases add a fallback href handler).
396
+
397
+ [{
398
+ handler: setLanguage,
399
+ eventTypes: [InternalCheckoutEvents.LanguageChanged]
400
+ }, {
401
+ handler: setIframeHeight,
402
+ eventTypes: [InternalCheckoutEvents.HeightChanged]
403
+ }, {
404
+ handler: onSession,
405
+ eventTypes: [CheckoutEvents.SessionLoaded, CheckoutEvents.SessionUpdated]
406
+ }, {
407
+ eventTypes: [CheckoutEvents.SessionPaymentOnHold],
408
+ handler: onPayment ? handleWithResult(sid, endpoint, onPayment) : followHref
409
+ }, {
410
+ eventTypes: [CheckoutEvents.SessionPaymentAuthorized],
411
+ handler: onPaymentAuthorized || onPayment ? handleWithResult(sid, endpoint, onPaymentAuthorized || onPayment) : followHref
412
+ }, {
413
+ handler: onSessionCancel ? handleWithResult(sid, endpoint, onSessionCancel) : followHref,
414
+ eventTypes: [CheckoutEvents.SessionCancel]
415
+ }, {
416
+ handler: onPaymentError ? handleWithResult(sid, endpoint, onPaymentError) : followHref,
417
+ eventTypes: [CheckoutEvents.SessionPaymentError]
418
+ }, {
419
+ handler: onSessionNotFound,
420
+ eventTypes: [CheckoutEvents.SessionNotFound]
421
+ }, {
422
+ handler: wrappedOnSessionLocked,
423
+ eventTypes: [CheckoutEvents.SessionLocked]
424
+ }, {
425
+ handler: onSessionLockFailed,
426
+ eventTypes: [CheckoutEvents.SessionLockFailed]
427
+ }, {
428
+ handler: onActivePaymentType,
429
+ eventTypes: [CheckoutEvents.ActivePaymentProductType]
430
+ }, {
431
+ handler: onActivePaymentType,
432
+ eventTypes: [CheckoutEvents.ActivePaymentProductType]
433
+ }, {
434
+ handler: wrappedOnValidateSession,
435
+ eventTypes: [CheckoutEvents.ValidateSession]
436
+ }].forEach(({
437
+ handler,
438
+ eventTypes
439
+ }) => {
440
+ if (handler) {
441
+ subscriptions.push(subscribe({
442
+ sid,
443
+ endpoint,
444
+ handler,
445
+ eventTypes,
446
+ checkout
447
+ }));
448
+ }
449
+ }); // Add iframe to DOM
450
+
451
+ await initiate(); // Return object with function to destroy the checkout.
452
+
453
+ return checkout;
454
+ };
455
+ /**
456
+ * Redirect the customer to a payment session in the Dintero Checkout.
457
+ */
458
+
459
+ const redirect = options => {
460
+ const {
461
+ sid,
462
+ language,
463
+ endpoint = "https://checkout.dintero.com"
464
+ } = options; // Redirect the current browser window to the checkout session url.
465
+
466
+ windowLocationAssign(getSessionUrl({
467
+ sid,
468
+ endpoint,
469
+ language,
470
+ shouldCallValidateSession: false
471
+ }));
472
+ };
473
+
474
+ exports.embed = embed;
475
+ exports.redirect = redirect;
@@ -0,0 +1,7 @@
1
+ 'use strict';
2
+
3
+ if (process.env.NODE_ENV === "production") {
4
+ module.exports = require("./dintero-checkout-web-sdk.cjs.prod.js");
5
+ } else {
6
+ module.exports = require("./dintero-checkout-web-sdk.cjs.dev.js");
7
+ }