@raydiant/playlist-window-manager 0.0.0-test-31 → 0.0.0-test29

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.
@@ -10,6 +10,7 @@ interface BrowserWindowRendererOptions {
10
10
  renderChildWindowsAsBrowserViews: boolean;
11
11
  useWindowPool: boolean;
12
12
  logger: Logger;
13
+ fullscreen?: boolean;
13
14
  proxySettings?: ProxySettings;
14
15
  windowCrashHandler?: () => void;
15
16
  }
@@ -94,7 +94,9 @@ var BrowserWindowRenderer = /** @class */ (function () {
94
94
  },
95
95
  });
96
96
  this.proxySettings = null;
97
- this.offscreenWindow.setBounds(opts.bounds);
97
+ if (!opts.fullscreen) {
98
+ this.offscreenWindow.setBounds(opts.bounds);
99
+ }
98
100
  if (opts.proxySettings) {
99
101
  this.proxySettings = opts.proxySettings;
100
102
  }
@@ -125,6 +127,7 @@ var BrowserWindowRenderer = /** @class */ (function () {
125
127
  : this.createOrGetPooledBrowserWindow(windowId, {
126
128
  show: false,
127
129
  frame: this.opts.frame,
130
+ fullscreen: this.opts.fullscreen,
128
131
  // NOTE: useWindowPool: true does not work with renderChildWindowsAsBrowserViews: false
129
132
  // because the parent can't be changed after creating the BrowserWindow.
130
133
  parent: parentWindowId
@@ -175,7 +178,9 @@ var BrowserWindowRenderer = /** @class */ (function () {
175
178
  // Electron issue: https://github.com/electron/electron/issues/20357
176
179
  window.view.setBackgroundColor(backgroundColor === 'transparent' ? '#00000000' : backgroundColor);
177
180
  }
178
- window.view.setBounds(window.bounds);
181
+ if (!this.opts.fullscreen) {
182
+ window.view.setBounds(window.bounds);
183
+ }
179
184
  if (!this.proxySettings) return [3 /*break*/, 2];
180
185
  return [4 /*yield*/, window.view.webContents.session.setProxy(this.proxySettings)];
181
186
  case 1:
@@ -9,6 +9,7 @@ export interface PlaylistWindowManagerOptions {
9
9
  device?: Device;
10
10
  readyTimeoutDurationSeconds?: number;
11
11
  appRendererUrl?: string;
12
+ appRendererOfflineSupport?: boolean;
12
13
  bounds?: WindowBounds;
13
14
  backgroundColor?: string;
14
15
  themeOverride?: Theme;
@@ -677,7 +677,7 @@ var PlaylistWindowManager = /** @class */ (function (_super) {
677
677
  }
678
678
  };
679
679
  PlaylistWindowManager.prototype.createWindow = function (pr) {
680
- var _a = this.options, readyTimeoutDurationSeconds = _a.readyTimeoutDurationSeconds, appRendererUrl = _a.appRendererUrl, backgroundColor = _a.backgroundColor, device = _a.device, logger = _a.logger, windowName = _a.windowName, parentWindowId = _a.parentWindowId, isPreview = _a.isPreview;
680
+ var _a = this.options, readyTimeoutDurationSeconds = _a.readyTimeoutDurationSeconds, appRendererUrl = _a.appRendererUrl, appRendererOfflineSupport = _a.appRendererOfflineSupport, backgroundColor = _a.backgroundColor, device = _a.device, logger = _a.logger, windowName = _a.windowName, parentWindowId = _a.parentWindowId, isPreview = _a.isPreview;
681
681
  if (!this.ruleEngine) {
682
682
  throw new Error('Attempted to create window but ruleEngine was not provided');
683
683
  }
@@ -712,6 +712,7 @@ var PlaylistWindowManager = /** @class */ (function (_super) {
712
712
  forceMute: this.forceMute,
713
713
  readyTimeoutDurationSeconds: readyTimeoutDurationSeconds,
714
714
  appRendererUrl: appRendererUrl,
715
+ appRendererOfflineSupport: appRendererOfflineSupport,
715
716
  bounds: this.bounds,
716
717
  backgroundColor: backgroundColor,
717
718
  playlistWindowManagerState: this.state,
@@ -894,7 +895,7 @@ var PlaylistWindowManager = /** @class */ (function (_super) {
894
895
  };
895
896
  PlaylistWindowManager.prototype.swapWindows = function () {
896
897
  return __awaiter(this, void 0, void 0, function () {
897
- var nextPreviewPresentationId, preview, result, shouldPreload;
898
+ var nextPreviewPresentationId, preview, result, nextPresentation, shouldPreload;
898
899
  return __generator(this, function (_a) {
899
900
  switch (_a.label) {
900
901
  case 0:
@@ -910,6 +911,7 @@ var PlaylistWindowManager = /** @class */ (function (_super) {
910
911
  preview = result.preview;
911
912
  nextPreviewPresentationId = preview.presentationId;
912
913
  }
914
+ nextPresentation = this.nextPresentation;
913
915
  // Set this.currentPresentationId before removing the current window to avoid timing issues with previewCheck
914
916
  // triggering during removeCurrentWindow. Current presentation id needs to be set to the next
915
917
  // presentation before calling shouldPreload().
@@ -939,6 +941,11 @@ var PlaylistWindowManager = /** @class */ (function (_super) {
939
941
  // Swap windows.
940
942
  this.currentWindow = this.nextWindow;
941
943
  if (this.currentWindow) {
944
+ // Restore this.currentPresentation value since if this.removeCurrentWindow()
945
+ // was called then this.currentPresentation was set to null.
946
+ // This fixes an issue where publishing a playlist with single presentation results
947
+ // in two iFrames created. See CX-2602 for more details.
948
+ this.currentPresentation = nextPresentation;
942
949
  this.currentWindow.onComplete(this.handleCurrentPresentationComplete);
943
950
  this.currentWindow.onError(this.handleCurrentPresentationError);
944
951
  this.currentWindow.onEnableInterruptLock(this.handleEnableInterruptLock);
@@ -23,6 +23,7 @@ export interface PresentationWindowOptions {
23
23
  renderer: PresentationWindowRenderer;
24
24
  readyTimeoutDurationSeconds?: number;
25
25
  appRendererUrl?: string;
26
+ appRendererOfflineSupport?: boolean;
26
27
  bounds?: WindowBounds;
27
28
  backgroundColor?: string;
28
29
  isPreview?: boolean;
@@ -102,7 +103,7 @@ export default class PresentationWindow {
102
103
  private isEmbeddedApp;
103
104
  private allChildWindowManagersReady;
104
105
  private checkIsReadyCallback;
105
- private appendWindowIdToHash;
106
+ private getFullAppRendererUrl;
106
107
  private loadEmbeddedApp;
107
108
  private loadLegacyApp;
108
109
  private createAndLoadWindow;
@@ -81,7 +81,7 @@ var PlaylistWindowManager_1 = __importDefault(require("./PlaylistWindowManager")
81
81
  var WindowTimeoutError_1 = __importDefault(require("./WindowTimeoutError"));
82
82
  var WindowLoadError_1 = __importDefault(require("./WindowLoadError"));
83
83
  // TODO: Automatically inject latest version when building in CI.
84
- var defaultAppRendererUrl = 'https://apps.raydiant.com/3.0.4/index.html';
84
+ var defaultAppRendererUrl = 'https://apps.raydiant.com/3.0.7/index.html';
85
85
  var isValidNumber = function (value) {
86
86
  return typeof value === 'number' && !isNaN(value);
87
87
  };
@@ -98,13 +98,7 @@ var isValidChargeRequest = function (value) {
98
98
  return value &&
99
99
  typeof value === 'object' &&
100
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');
101
+ typeof value.amount === 'number';
108
102
  };
109
103
  var PresentationWindow = /** @class */ (function () {
110
104
  function PresentationWindow(options) {
@@ -696,10 +690,14 @@ var PresentationWindow = /** @class */ (function () {
696
690
  }
697
691
  }
698
692
  };
699
- PresentationWindow.prototype.appendWindowIdToHash = function (urlStr, windowId) {
700
- var url = new URL(urlStr);
693
+ PresentationWindow.prototype.getFullAppRendererUrl = function (_a) {
694
+ var appRendererUrl = _a.appRendererUrl, windowId = _a.windowId, appRendererOfflineSupport = _a.appRendererOfflineSupport;
695
+ var url = new URL(appRendererUrl);
701
696
  var hashParams = new URLSearchParams(url.hash.slice(1));
702
697
  hashParams.set('__raydiantWindowId', windowId);
698
+ if (appRendererOfflineSupport === true) {
699
+ hashParams.set('__raydiantOfflineSupport', 'true');
700
+ }
703
701
  url.hash = hashParams.toString();
704
702
  return url.toString();
705
703
  };
@@ -730,13 +728,17 @@ var PresentationWindow = /** @class */ (function () {
730
728
  };
731
729
  PresentationWindow.prototype.loadLegacyApp = function () {
732
730
  return __awaiter(this, void 0, void 0, function () {
733
- var _a, windowId, _b, appRendererUrl, backgroundColor;
731
+ var _a, windowId, _b, appRendererUrl, appRendererOfflineSupport, backgroundColor;
734
732
  return __generator(this, function (_c) {
735
733
  switch (_c.label) {
736
734
  case 0:
737
- _a = this.options, windowId = _a.windowId, _b = _a.appRendererUrl, appRendererUrl = _b === void 0 ? defaultAppRendererUrl : _b, backgroundColor = _a.backgroundColor;
735
+ _a = this.options, windowId = _a.windowId, _b = _a.appRendererUrl, appRendererUrl = _b === void 0 ? defaultAppRendererUrl : _b, appRendererOfflineSupport = _a.appRendererOfflineSupport, backgroundColor = _a.backgroundColor;
738
736
  this.logInfo("Create window '".concat(windowId, "'"));
739
- return [4 /*yield*/, this.createAndLoadWindow(this.appendWindowIdToHash(appRendererUrl, windowId), backgroundColor || '#000000', // Default to black bg for Raydiant apps
737
+ return [4 /*yield*/, this.createAndLoadWindow(this.getFullAppRendererUrl({
738
+ appRendererUrl: appRendererUrl,
739
+ windowId: windowId,
740
+ appRendererOfflineSupport: appRendererOfflineSupport,
741
+ }), backgroundColor || '#000000', // Default to black bg for Raydiant apps
740
742
  this.handleLegacyMessage)];
741
743
  case 1:
742
744
  _c.sent();
@@ -1040,12 +1042,16 @@ var PresentationWindow = /** @class */ (function () {
1040
1042
  }
1041
1043
  };
1042
1044
  PresentationWindow.prototype.getEmbeddedAppUrl = function () {
1043
- var windowId = this.options.windowId;
1045
+ var _a = this.options, windowId = _a.windowId, appRendererOfflineSupport = _a.appRendererOfflineSupport;
1044
1046
  var metadata = {
1045
1047
  renderMode: this.options.isPreview ? 'preview' : 'live',
1046
1048
  };
1047
1049
  var url = (0, embeddedApps_1.default)(this.presentation, this.options.applicationVersion, metadata);
1048
- return this.appendWindowIdToHash(url, windowId);
1050
+ return this.getFullAppRendererUrl({
1051
+ appRendererUrl: url,
1052
+ windowId: windowId,
1053
+ appRendererOfflineSupport: appRendererOfflineSupport,
1054
+ });
1049
1055
  };
1050
1056
  PresentationWindow.prototype.handleReady = function () {
1051
1057
  this.didReceiveReady = true;
@@ -24,6 +24,9 @@ function createEmbeddedApp(presentation, applicationVersion, metadata) {
24
24
  if (metadataKey === 'renderMode') {
25
25
  value = metadata.renderMode;
26
26
  }
27
+ else if (metadataKey === 'token') {
28
+ value = presentation.token;
29
+ }
27
30
  }
28
31
  else {
29
32
  // Don't replace variables that are numbers to allow setting
@@ -121,3 +121,10 @@ test('File input uses url as value', function () {
121
121
  presentationProperties: [{ type: 'file', name: 'file' }],
122
122
  }), createMetadata())).toBe("https://example.come?image=".concat(encodeURIComponent('https://image.png')));
123
123
  });
124
+ test('Replaces $token with presentation token', function () {
125
+ var presentation = createPresentation({ token: 'abc' });
126
+ var applicationVersion = createApplicationVersion({
127
+ embeddedUrlFormat: 'https://example.com?token=:$token',
128
+ });
129
+ expect((0, embeddedApps_1.default)(presentation, applicationVersion, createMetadata())).toBe('https://example.com?token=abc');
130
+ });
package/build/types.d.ts CHANGED
@@ -19,6 +19,7 @@ export interface Presentation {
19
19
  playlistId: string;
20
20
  }>;
21
21
  };
22
+ token?: string;
22
23
  }
23
24
  export interface ApplicationVersion {
24
25
  id: string;
@@ -143,8 +144,13 @@ export interface AnalyticsEvent {
143
144
  export interface ChargeRequest {
144
145
  requestId: string;
145
146
  amount: number;
146
- tags?: Record<string, undefined | null | boolean | number | string>;
147
- idempotencyId?: string;
147
+ items: Array<{
148
+ name: string;
149
+ price: number;
150
+ description?: string;
151
+ sku?: string;
152
+ quantity?: number;
153
+ }>;
148
154
  }
149
155
  export interface Charge {
150
156
  id: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@raydiant/playlist-window-manager",
3
- "version": "0.0.0-test-31",
3
+ "version": "0.0.0-test29",
4
4
  "description": "Window manager for playlist playback.",
5
5
  "main": "build/index.js",
6
6
  "scripts": {
@@ -45,6 +45,7 @@ interface BrowserWindowRendererOptions {
45
45
  renderChildWindowsAsBrowserViews: boolean;
46
46
  useWindowPool: boolean;
47
47
  logger: Logger;
48
+ fullscreen?: boolean;
48
49
  proxySettings?: ProxySettings;
49
50
  windowCrashHandler?: () => void;
50
51
  }
@@ -76,7 +77,9 @@ export default class BrowserWindowRenderer
76
77
  private logger: Logger;
77
78
 
78
79
  constructor(private opts: BrowserWindowRendererOptions) {
79
- this.offscreenWindow.setBounds(opts.bounds);
80
+ if (!opts.fullscreen) {
81
+ this.offscreenWindow.setBounds(opts.bounds);
82
+ }
80
83
  if (opts.proxySettings) {
81
84
  this.proxySettings = opts.proxySettings;
82
85
  }
@@ -111,6 +114,7 @@ export default class BrowserWindowRenderer
111
114
  : this.createOrGetPooledBrowserWindow(windowId, {
112
115
  show: false,
113
116
  frame: this.opts.frame,
117
+ fullscreen: this.opts.fullscreen,
114
118
  // NOTE: useWindowPool: true does not work with renderChildWindowsAsBrowserViews: false
115
119
  // because the parent can't be changed after creating the BrowserWindow.
116
120
  parent: parentWindowId
@@ -200,7 +204,9 @@ export default class BrowserWindowRenderer
200
204
  );
201
205
  }
202
206
 
203
- window.view.setBounds(window.bounds);
207
+ if (!this.opts.fullscreen) {
208
+ window.view.setBounds(window.bounds);
209
+ }
204
210
 
205
211
  if (this.proxySettings) {
206
212
  await window.view.webContents.session.setProxy(this.proxySettings);
@@ -40,6 +40,10 @@ export interface PlaylistWindowManagerOptions {
40
40
  // Override the default app renderer url
41
41
  appRendererUrl?: string;
42
42
 
43
+ // App renderer offline support.
44
+ // If true, the app renderer will be using service worker to cache resources for offline support.
45
+ appRendererOfflineSupport?: boolean;
46
+
43
47
  // The bounds of the window manager, used for child windows
44
48
  bounds?: WindowBounds;
45
49
 
@@ -488,6 +492,7 @@ export default class PlaylistWindowManager extends EventEmitter {
488
492
  const {
489
493
  readyTimeoutDurationSeconds,
490
494
  appRendererUrl,
495
+ appRendererOfflineSupport,
491
496
  backgroundColor,
492
497
  device,
493
498
  logger,
@@ -541,6 +546,7 @@ export default class PlaylistWindowManager extends EventEmitter {
541
546
  forceMute: this.forceMute,
542
547
  readyTimeoutDurationSeconds,
543
548
  appRendererUrl,
549
+ appRendererOfflineSupport,
544
550
  bounds: this.bounds,
545
551
  backgroundColor,
546
552
  playlistWindowManagerState: this.state,
@@ -698,6 +704,9 @@ export default class PlaylistWindowManager extends EventEmitter {
698
704
  nextPreviewPresentationId = preview.presentationId;
699
705
  }
700
706
 
707
+ // Save reference to next presentation since later call to
708
+ // this.removeCurrentWindow() will set this.currentPresentation to null.
709
+ const nextPresentation = this.nextPresentation;
701
710
  // Set this.currentPresentationId before removing the current window to avoid timing issues with previewCheck
702
711
  // triggering during removeCurrentWindow. Current presentation id needs to be set to the next
703
712
  // presentation before calling shouldPreload().
@@ -734,6 +743,11 @@ export default class PlaylistWindowManager extends EventEmitter {
734
743
  // Swap windows.
735
744
  this.currentWindow = this.nextWindow;
736
745
  if (this.currentWindow) {
746
+ // Restore this.currentPresentation value since if this.removeCurrentWindow()
747
+ // was called then this.currentPresentation was set to null.
748
+ // This fixes an issue where publishing a playlist with single presentation results
749
+ // in two iFrames created. See CX-2602 for more details.
750
+ this.currentPresentation = nextPresentation;
737
751
  this.currentWindow.onComplete(this.handleCurrentPresentationComplete);
738
752
  this.currentWindow.onError(this.handleCurrentPresentationError);
739
753
  this.currentWindow.onEnableInterruptLock(this.handleEnableInterruptLock);
@@ -47,6 +47,7 @@ export interface PresentationWindowOptions {
47
47
  renderer: PresentationWindowRenderer;
48
48
  readyTimeoutDurationSeconds?: number;
49
49
  appRendererUrl?: string;
50
+ appRendererOfflineSupport?: boolean;
50
51
  bounds?: WindowBounds;
51
52
  backgroundColor?: string;
52
53
  isPreview?: boolean;
@@ -60,7 +61,7 @@ export interface PresentationWindowOptions {
60
61
  }
61
62
 
62
63
  // TODO: Automatically inject latest version when building in CI.
63
- const defaultAppRendererUrl = 'https://apps.raydiant.com/3.0.4/index.html';
64
+ const defaultAppRendererUrl = 'https://apps.raydiant.com/3.0.7/index.html';
64
65
 
65
66
  const isValidNumber = (value: any) =>
66
67
  typeof value === 'number' && !isNaN(value);
@@ -78,13 +79,7 @@ const isValidChargeRequest = (value: any): value is ChargeRequest =>
78
79
  value &&
79
80
  typeof value === 'object' &&
80
81
  typeof value.requestId === 'string' &&
81
- typeof value.amount === 'number' &&
82
- (value.tags === undefined ||
83
- value.tags === null ||
84
- typeof value.tags === 'object') &&
85
- (value.idempotencyId === undefined ||
86
- value.idempotencyId === null ||
87
- typeof value.idempotencyId === 'string');
82
+ typeof value.amount === 'number';
88
83
 
89
84
  export default class PresentationWindow {
90
85
  private didReceiveReady: boolean = false;
@@ -494,10 +489,21 @@ export default class PresentationWindow {
494
489
  }
495
490
  }
496
491
 
497
- private appendWindowIdToHash(urlStr: string, windowId: string) {
498
- const url = new URL(urlStr);
492
+ private getFullAppRendererUrl({
493
+ appRendererUrl,
494
+ windowId,
495
+ appRendererOfflineSupport,
496
+ }: {
497
+ appRendererUrl: string;
498
+ windowId: string;
499
+ appRendererOfflineSupport: boolean | undefined;
500
+ }) {
501
+ const url = new URL(appRendererUrl);
499
502
  const hashParams = new URLSearchParams(url.hash.slice(1));
500
503
  hashParams.set('__raydiantWindowId', windowId);
504
+ if (appRendererOfflineSupport === true) {
505
+ hashParams.set('__raydiantOfflineSupport', 'true');
506
+ }
501
507
  url.hash = hashParams.toString();
502
508
 
503
509
  return url.toString();
@@ -531,13 +537,18 @@ export default class PresentationWindow {
531
537
  const {
532
538
  windowId,
533
539
  appRendererUrl = defaultAppRendererUrl,
540
+ appRendererOfflineSupport,
534
541
  backgroundColor,
535
542
  } = this.options;
536
543
 
537
544
  this.logInfo(`Create window '${windowId}'`);
538
545
 
539
546
  await this.createAndLoadWindow(
540
- this.appendWindowIdToHash(appRendererUrl, windowId),
547
+ this.getFullAppRendererUrl({
548
+ appRendererUrl,
549
+ windowId,
550
+ appRendererOfflineSupport,
551
+ }),
541
552
  backgroundColor || '#000000', // Default to black bg for Raydiant apps
542
553
  this.handleLegacyMessage
543
554
  );
@@ -867,7 +878,7 @@ export default class PresentationWindow {
867
878
  }
868
879
 
869
880
  private getEmbeddedAppUrl() {
870
- const { windowId } = this.options;
881
+ const { windowId, appRendererOfflineSupport } = this.options;
871
882
 
872
883
  const metadata: EmbeddedAppMetadata = {
873
884
  renderMode: this.options.isPreview ? 'preview' : 'live',
@@ -879,7 +890,11 @@ export default class PresentationWindow {
879
890
  metadata
880
891
  );
881
892
 
882
- return this.appendWindowIdToHash(url, windowId);
893
+ return this.getFullAppRendererUrl({
894
+ appRendererUrl: url,
895
+ windowId,
896
+ appRendererOfflineSupport,
897
+ });
883
898
  }
884
899
 
885
900
  private handleEmbeddedMessage = async (type: string, payload?: any) => {
@@ -229,3 +229,14 @@ test('File input uses url as value', () => {
229
229
  `https://example.come?image=${encodeURIComponent('https://image.png')}`
230
230
  );
231
231
  });
232
+
233
+ test('Replaces $token with presentation token', () => {
234
+ const presentation = createPresentation({ token: 'abc' });
235
+ const applicationVersion = createApplicationVersion({
236
+ embeddedUrlFormat: 'https://example.com?token=:$token',
237
+ });
238
+
239
+ expect(
240
+ createEmbeddedApp(presentation, applicationVersion, createMetadata())
241
+ ).toBe('https://example.com?token=abc');
242
+ });
@@ -32,6 +32,8 @@ export default function createEmbeddedApp(
32
32
  const metadataKey = variableName.slice(1);
33
33
  if (metadataKey === 'renderMode') {
34
34
  value = metadata.renderMode;
35
+ } else if (metadataKey === 'token') {
36
+ value = presentation.token;
35
37
  }
36
38
  } else {
37
39
  // Don't replace variables that are numbers to allow setting
package/src/types.ts CHANGED
@@ -16,6 +16,7 @@ export interface Presentation {
16
16
  };
17
17
  presentationsPlaylists: Array<{ playlistId: string }>;
18
18
  };
19
+ token?: string;
19
20
  }
20
21
 
21
22
  export interface ApplicationVersion {
@@ -177,8 +178,13 @@ export interface AnalyticsEvent {
177
178
  export interface ChargeRequest {
178
179
  requestId: string;
179
180
  amount: number;
180
- tags?: Record<string, undefined | null | boolean | number | string>;
181
- idempotencyId?: string;
181
+ items: Array<{
182
+ name: string;
183
+ price: number;
184
+ description?: string;
185
+ sku?: string;
186
+ quantity?: number;
187
+ }>;
182
188
  }
183
189
 
184
190
  export interface Charge {
@@ -10,4 +10,4 @@ mkdir build
10
10
  yarn build
11
11
 
12
12
  # Publish
13
- yarn publish --non-interactive --access public
13
+ yarn publish --access public