@raydiant/playlist-window-manager 0.0.0-test-27 → 0.0.0-test-28

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.
@@ -94,6 +94,18 @@ var isValidAnalyticsEvent = function (value) {
94
94
  value.productCategory === undefined ||
95
95
  value.productCategory === null);
96
96
  };
97
+ var isValidChargeRequest = function (value) {
98
+ return value &&
99
+ typeof value === 'object' &&
100
+ typeof value.requestId === 'string' &&
101
+ typeof value.amount === 'number' &&
102
+ (value.tags === undefined ||
103
+ value.tags === null ||
104
+ typeof value.tags === 'object') &&
105
+ (value.idempotencyId === undefined ||
106
+ value.idempotencyId === null ||
107
+ typeof value.idempotencyId === 'string');
108
+ };
97
109
  var PresentationWindow = /** @class */ (function () {
98
110
  function PresentationWindow(options) {
99
111
  var _this = this;
@@ -114,6 +126,7 @@ var PresentationWindow = /** @class */ (function () {
114
126
  this.enableInterruptLockCallback = null;
115
127
  this.disableInterruptLockCallback = null;
116
128
  this.analyticsEventCallback = null;
129
+ this.chargeRequestCallback = null;
117
130
  this.forceMute = false;
118
131
  this.error = null;
119
132
  this.workerState = {};
@@ -121,6 +134,7 @@ var PresentationWindow = /** @class */ (function () {
121
134
  this.runtimeSubscriptions = new Set();
122
135
  this.previewSubscriptions = new Set();
123
136
  this.previewState = { inputs: {} };
137
+ this.paymentSubscriptions = new Set();
124
138
  this.createObjectURLResolvers = {};
125
139
  this.createObjectURLTimeouts = {};
126
140
  this.handleEmbeddedMessage = function (type, payload) { return __awaiter(_this, void 0, void 0, function () {
@@ -200,8 +214,13 @@ var PresentationWindow = /** @class */ (function () {
200
214
  break;
201
215
  }
202
216
  case 'analytics-event': {
203
- if (this.analyticsEventCallback && isValidAnalyticsEvent(payload)) {
204
- this.analyticsEventCallback(payload);
217
+ if (isValidAnalyticsEvent(payload)) {
218
+ if (this.analyticsEventCallback) {
219
+ this.analyticsEventCallback(payload);
220
+ }
221
+ }
222
+ else {
223
+ this.logWarning("Invalid payload for analytics-event message: ".concat(payload));
205
224
  }
206
225
  break;
207
226
  }
@@ -245,6 +264,44 @@ var PresentationWindow = /** @class */ (function () {
245
264
  }
246
265
  break;
247
266
  }
267
+ case 'payments-charge-request': {
268
+ if (isValidChargeRequest(payload)) {
269
+ if (this.chargeRequestCallback) {
270
+ this.chargeRequestCallback(payload);
271
+ }
272
+ }
273
+ else {
274
+ this.logWarning("Invalid payload for payments-charge-request message: ".concat(payload));
275
+ }
276
+ break;
277
+ }
278
+ case 'payments-subscribe': {
279
+ if (typeof payload === 'string') {
280
+ this.logInfo("Received 'worker-subscribe' from window '".concat(windowId, "'"));
281
+ // The payload is the payment subscription type (ex. 'charge', 'terminal')
282
+ this.paymentSubscriptions.add(payload);
283
+ // Immediately send terminal when subscribing.
284
+ if (payload === 'terminal' && this.options.getTerminal) {
285
+ this.sendMessageObject('payments-terminal-event', {
286
+ terminal: this.options.getTerminal(),
287
+ });
288
+ }
289
+ }
290
+ else {
291
+ this.logWarning("Invalid payload for payments-subscribe message: ".concat(payload));
292
+ }
293
+ break;
294
+ }
295
+ case 'payments-unsubscribe': {
296
+ if (typeof payload === 'string') {
297
+ this.logInfo("Received 'payments-unsubscribe' from window '".concat(windowId, "'"));
298
+ this.paymentSubscriptions.delete(payload);
299
+ }
300
+ else {
301
+ this.logWarning("Invalid payload for payments-unsubscribe message: ".concat(payload));
302
+ }
303
+ break;
304
+ }
248
305
  default: {
249
306
  this.logWarning("Received unknown embedded message type: ".concat(type));
250
307
  }
@@ -480,6 +537,9 @@ var PresentationWindow = /** @class */ (function () {
480
537
  PresentationWindow.prototype.onAnalyticsEvent = function (callback) {
481
538
  this.analyticsEventCallback = callback;
482
539
  };
540
+ PresentationWindow.prototype.onChargeRequest = function (callback) {
541
+ this.chargeRequestCallback = callback;
542
+ };
483
543
  PresentationWindow.prototype.isReady = function () {
484
544
  // TODO: To support the 'ready' event in embedded apps, they will need to tell the
485
545
  // runtime that it should wait for ready instead of DOMLoaded. This could be a "wait
@@ -571,6 +631,39 @@ var PresentationWindow = /** @class */ (function () {
571
631
  });
572
632
  });
573
633
  };
634
+ PresentationWindow.prototype.sendChargeResponse = function (response) {
635
+ // TODO: Instead of sending the charge to all windows, we should only send it to the app
636
+ // that requested the charge. We probably don't want to use the windowId to avoid missing
637
+ // the events in case the window was closed/restarted. Since we are only sending the charge
638
+ // id and status this seems ok for now but need to be mindful of sending any sensitive data.
639
+ this.sendMessageObject('payments-charge-response', {
640
+ requestId: response.requestId,
641
+ charge: response.charge,
642
+ error: response.error,
643
+ });
644
+ // Forward the event to the child window managers.
645
+ Object.values(this.windowManagers).forEach(function (wm) {
646
+ return wm.sendChargeResponse(response);
647
+ });
648
+ };
649
+ PresentationWindow.prototype.sendCharge = function (charge) {
650
+ // TODO: Instead of sending the charge to all windows, we should only send it to the app
651
+ // that requested the charge.
652
+ if (this.paymentSubscriptions.has('charge')) {
653
+ this.sendMessageObject('payments-charge-event', { charge: charge });
654
+ }
655
+ // Forward the event to the child window managers.
656
+ Object.values(this.windowManagers).forEach(function (wm) { return wm.sendCharge(charge); });
657
+ };
658
+ PresentationWindow.prototype.sendTerminal = function (terminal) {
659
+ if (this.paymentSubscriptions.has('terminal')) {
660
+ this.sendMessageObject('payments-terminal-event', { terminal: terminal });
661
+ }
662
+ // Forward the event to the child window managers.
663
+ Object.values(this.windowManagers).forEach(function (wm) {
664
+ return wm.sendTerminal(terminal);
665
+ });
666
+ };
574
667
  PresentationWindow.prototype.isEmbeddedApp = function () {
575
668
  var _a = this.options, applicationVersion = _a.applicationVersion, isPreview = _a.isPreview;
576
669
  // If the application has a source url, always use it for rendering the preview.
@@ -657,17 +750,15 @@ var PresentationWindow = /** @class */ (function () {
657
750
  };
658
751
  PresentationWindow.prototype.createAndLoadWindow = function (url, backgroundColor, receiveMessageCallback) {
659
752
  return __awaiter(this, void 0, void 0, function () {
660
- var _a, windowId, parentWindowId, renderer, bounds, logger;
753
+ var _a, windowId, parentWindowId, renderer, bounds;
661
754
  return __generator(this, function (_b) {
662
755
  switch (_b.label) {
663
756
  case 0:
664
- _a = this.options, windowId = _a.windowId, parentWindowId = _a.parentWindowId, renderer = _a.renderer, bounds = _a.bounds, logger = _a.logger;
665
- logger.info("playlist-window-manager/src/PresentationWindow.ts createAndLoadWindow1: ".concat(JSON.stringify(bounds)));
757
+ _a = this.options, windowId = _a.windowId, parentWindowId = _a.parentWindowId, renderer = _a.renderer, bounds = _a.bounds;
666
758
  renderer.createWindow({
667
759
  windowId: windowId,
668
760
  parentWindowId: parentWindowId,
669
761
  bounds: bounds,
670
- logger: logger,
671
762
  backgroundColor: backgroundColor,
672
763
  receiveMessageCallback: receiveMessageCallback,
673
764
  errorCallback: this.handleError,
@@ -820,9 +911,7 @@ var PresentationWindow = /** @class */ (function () {
820
911
  didBoundsChange = prevBounds
821
912
  ? !(0, fast_deep_equal_1.default)(bounds, prevBounds)
822
913
  : true;
823
- this.logInfo("playlist-window-manager/src/PresentationWindow.ts openChildWindow1: ".concat(JSON.stringify(prevBounds)));
824
914
  if (didBoundsChange) {
825
- this.logInfo("playlist-window-manager/src/PresentationWindow.ts openChildWindow2: ".concat(JSON.stringify(bounds)));
826
915
  windowManager.updateBounds(bounds);
827
916
  }
828
917
  didForceMuteChange = forceMute !== prevForceMute;
@@ -842,7 +931,6 @@ var PresentationWindow = /** @class */ (function () {
842
931
  }
843
932
  return [3 /*break*/, 3];
844
933
  case 1:
845
- this.logInfo("playlist-window-manager/src/PresentationWindow.ts openChildWindow3: ".concat(JSON.stringify(bounds)));
846
934
  windowManager = new PlaylistWindowManager_1.default({
847
935
  parentWindowId: windowId,
848
936
  windowName: windowName,
@@ -864,6 +952,7 @@ var PresentationWindow = /** @class */ (function () {
864
952
  isPreview: isPreview,
865
953
  onEnableInterruptLock: function () { return _this.enableInteruptLock(windowName); },
866
954
  onDisableInterruptLock: function () { return _this.disableInteruptLock(windowName); },
955
+ getTerminal: this.options.getTerminal,
867
956
  });
868
957
  // Hook up child window manager events to bubble up to the parent.
869
958
  if (parentWindowManager) {
@@ -882,6 +971,9 @@ var PresentationWindow = /** @class */ (function () {
882
971
  windowManager.on('window_analytics_event', function (metadata) {
883
972
  parentWindowManager.emit('window_analytics_event', metadata);
884
973
  });
974
+ windowManager.on('window_charge_request', function (metadata) {
975
+ parentWindowManager.emit('window_charge_request', metadata);
976
+ });
885
977
  }
886
978
  this.windowManagers[windowName] = windowManager;
887
979
  windowManager.setRenderer(renderer);
@@ -238,4 +238,103 @@ describe('embedded apps', function () {
238
238
  });
239
239
  }); });
240
240
  });
241
+ describe('payments', function () {
242
+ test('charge request', function () { return __awaiter(void 0, void 0, void 0, function () {
243
+ var testRenderer, window, callback;
244
+ return __generator(this, function (_a) {
245
+ switch (_a.label) {
246
+ case 0:
247
+ testRenderer = (0, testUtils_1.createRenderer)();
248
+ window = (0, testUtils_1.createPresentationWindow)({
249
+ windowId: 'test-charge-request',
250
+ presentation: (0, testUtils_1.createPresentation)(),
251
+ applicationVersion: (0, testUtils_1.createApplicationVersion)({
252
+ embeddedUrlFormat: 'http://test.local/:input',
253
+ }),
254
+ renderer: testRenderer,
255
+ });
256
+ callback = jest.fn();
257
+ window.onChargeRequest(callback);
258
+ return [4 /*yield*/, window.load()];
259
+ case 1:
260
+ _a.sent();
261
+ testRenderer.runReceiveMessageCallback('payments-charge-request', {
262
+ requestId: 'test',
263
+ amount: 100,
264
+ });
265
+ expect(callback).toHaveBeenCalledWith({
266
+ requestId: 'test',
267
+ amount: 100,
268
+ });
269
+ // Send charge response.
270
+ window.sendChargeResponse({
271
+ requestId: 'test',
272
+ charge: { id: '1', status: 'pending' },
273
+ });
274
+ expect(testRenderer.sendMessageObject).toHaveBeenCalledWith('test-charge-request', 'payments-charge-response', { requestId: 'test', charge: { id: '1', status: 'pending' } });
275
+ return [2 /*return*/];
276
+ }
277
+ });
278
+ }); });
279
+ test('subscribe to charge', function () { return __awaiter(void 0, void 0, void 0, function () {
280
+ var testRenderer, window;
281
+ return __generator(this, function (_a) {
282
+ switch (_a.label) {
283
+ case 0:
284
+ testRenderer = (0, testUtils_1.createRenderer)();
285
+ window = (0, testUtils_1.createPresentationWindow)({
286
+ windowId: 'test-payments-subscribe-charge',
287
+ presentation: (0, testUtils_1.createPresentation)(),
288
+ applicationVersion: (0, testUtils_1.createApplicationVersion)({
289
+ embeddedUrlFormat: 'http://test.local/:input',
290
+ }),
291
+ renderer: testRenderer,
292
+ });
293
+ return [4 /*yield*/, window.load()];
294
+ case 1:
295
+ _a.sent();
296
+ testRenderer.runReceiveMessageCallback('payments-subscribe', 'charge');
297
+ window.sendCharge({ id: 'test', status: 'success' });
298
+ expect(testRenderer.sendMessageObject).toHaveBeenCalledWith('test-payments-subscribe-charge', 'payments-charge-event', { charge: { id: 'test', status: 'success' } });
299
+ // Unsubscribe should not send a message.
300
+ testRenderer.runReceiveMessageCallback('payments-unsubscribe', 'charge');
301
+ window.sendCharge({ id: 'test2', status: 'success' });
302
+ expect(testRenderer.sendMessageObject).toHaveBeenCalledTimes(1);
303
+ return [2 /*return*/];
304
+ }
305
+ });
306
+ }); });
307
+ test('subscribe to terminal', function () { return __awaiter(void 0, void 0, void 0, function () {
308
+ var testRenderer, window;
309
+ return __generator(this, function (_a) {
310
+ switch (_a.label) {
311
+ case 0:
312
+ testRenderer = (0, testUtils_1.createRenderer)();
313
+ window = (0, testUtils_1.createPresentationWindow)({
314
+ windowId: 'test-payments-subscribe-terminal',
315
+ presentation: (0, testUtils_1.createPresentation)(),
316
+ applicationVersion: (0, testUtils_1.createApplicationVersion)({
317
+ embeddedUrlFormat: 'http://test.local/:input',
318
+ }),
319
+ renderer: testRenderer,
320
+ getTerminal: function () { return null; },
321
+ });
322
+ return [4 /*yield*/, window.load()];
323
+ case 1:
324
+ _a.sent();
325
+ testRenderer.runReceiveMessageCallback('payments-subscribe', 'terminal');
326
+ // Terminal subscriptions should receive the current terminal immediately after subscribing.
327
+ expect(testRenderer.sendMessageObject).toHaveBeenCalledWith('test-payments-subscribe-terminal', 'payments-terminal-event', { terminal: null });
328
+ // Send terminal update event.
329
+ window.sendTerminal({ status: 'open' });
330
+ expect(testRenderer.sendMessageObject).toHaveBeenCalledWith('test-payments-subscribe-terminal', 'payments-terminal-event', { terminal: { status: 'open' } });
331
+ // Unsubscribe should not send a message.
332
+ testRenderer.runReceiveMessageCallback('payments-unsubscribe', 'terminal');
333
+ window.sendTerminal({ status: 'closed' });
334
+ expect(testRenderer.sendMessageObject).toHaveBeenCalledTimes(2);
335
+ return [2 /*return*/];
336
+ }
337
+ });
338
+ }); });
339
+ });
241
340
  // TODO: Backfill tests for all legacy and embedded apps.
@@ -98,6 +98,7 @@ function createPresentationWindow(overrides) {
98
98
  muteWindow: function () { },
99
99
  unMuteWindow: function () { },
100
100
  },
101
+ getTerminal: overrides.getTerminal,
101
102
  });
102
103
  }
103
104
  exports.createPresentationWindow = createPresentationWindow;
package/build/types.d.ts CHANGED
@@ -82,7 +82,6 @@ export interface CreateWindowOptions {
82
82
  windowId: string;
83
83
  parentWindowId?: string;
84
84
  bounds?: WindowBounds;
85
- logger: Logger;
86
85
  backgroundColor?: string;
87
86
  receiveMessageCallback?: (type: string, payload?: any) => void;
88
87
  errorCallback: (err: any) => void;
@@ -141,3 +140,23 @@ export interface AnalyticsEvent {
141
140
  source: string;
142
141
  productCategory?: string | null;
143
142
  }
143
+ export interface ChargeRequest {
144
+ requestId: string;
145
+ amount: number;
146
+ tags?: Record<string, undefined | null | boolean | number | string>;
147
+ idempotencyId?: string;
148
+ }
149
+ export interface Charge {
150
+ id: string;
151
+ status: string;
152
+ }
153
+ export interface ChargeResponse {
154
+ requestId: string;
155
+ charge?: Charge;
156
+ error?: {
157
+ message: string;
158
+ };
159
+ }
160
+ export interface Terminal {
161
+ status: string;
162
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@raydiant/playlist-window-manager",
3
- "version": "0.0.0-test-27",
3
+ "version": "0.0.0-test-28",
4
4
  "description": "Window manager for playlist playback.",
5
5
  "main": "build/index.js",
6
6
  "scripts": {
@@ -11,20 +11,18 @@
11
11
  "deploy": "sh tasks/npm-publish.sh"
12
12
  },
13
13
  "dependencies": {
14
- "@raydiant/playlist-rule-engine": "3.2.2",
15
- "eventemitter3": "^4.0.7",
16
14
  "fast-deep-equal": "^3.1.3",
17
- "lodash": "^4.17.21",
15
+ "@raydiant/playlist-rule-engine": "3.2.2",
18
16
  "raydiant-kit": "4.7.3",
19
- "uuid": "^8.3.0"
17
+ "uuid": "^8.3.0",
18
+ "eventemitter3": "^4.0.7"
20
19
  },
21
20
  "devDependencies": {
22
21
  "@babel/core": "^7.5.5",
23
- "@types/jest": "^24.0.15",
24
22
  "@types/jschannel": "^1.0.1",
25
- "@types/lodash": "^4.14.200",
23
+ "@types/jest": "^24.0.15",
26
24
  "@types/uuid": "8.3.0",
27
- "electron": "10.3.2",
25
+ "electron": "28.1.2",
28
26
  "jest": "^24.8.0",
29
27
  "ts-jest": "^24.0.2",
30
28
  "typescript": "^4.1.2"
@@ -30,16 +30,9 @@ export default class BrowserViewRenderer implements PresentationWindowRenderer {
30
30
  windowId,
31
31
  parentWindowId,
32
32
  bounds,
33
- logger,
34
33
  backgroundColor,
35
34
  receiveMessageCallback,
36
35
  }: CreateWindowOptions) {
37
- logger.info(
38
- `playlist-window-manager/src/BrowserViewRenderer.ts createWindow1 ${JSON.stringify(
39
- bounds || { ...this.mainWindow.getBounds(), x: 0, y: 0 }
40
- )}`
41
- );
42
-
43
36
  const window = {
44
37
  view: new BrowserView({
45
38
  webPreferences: {
@@ -65,17 +58,7 @@ export default class BrowserViewRenderer implements PresentationWindowRenderer {
65
58
  ipcMain.on(windowId, window.receiveMessageCallback);
66
59
 
67
60
  this.offscreenWindow.addBrowserView(window.view);
68
- logger.info(
69
- `playlist-window-manager/src/BrowserViewRenderer.ts createWindow2 ${JSON.stringify(
70
- window.bounds
71
- )}`
72
- );
73
61
  window.view.setBounds(window.bounds);
74
- logger.info(
75
- `playlist-window-manager/src/BrowserViewRenderer.ts createWindow3 ${JSON.stringify(
76
- window.view.getBounds()
77
- )}`
78
- );
79
62
 
80
63
  if (backgroundColor) {
81
64
  window.view.setBackgroundColor(backgroundColor);
@@ -107,7 +90,7 @@ export default class BrowserViewRenderer implements PresentationWindowRenderer {
107
90
  `Failed to update window bounds, missing window id '${windowId}'`
108
91
  );
109
92
  }
110
- // TODO log bounds
93
+
111
94
  window.bounds = bounds;
112
95
  window.view.setBounds(window.bounds);
113
96
  }