@monterosa/sdk-launcher-kit 2.0.0-rc.2 → 2.0.0-rc.3
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.
- package/dist/index.cjs +1939 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.js +1 -1
- package/package.json +8 -7
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,1939 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var sdkCore = require('@monterosa/sdk-core');
|
|
6
|
+
var sdkUtil = require('@monterosa/sdk-util');
|
|
7
|
+
var sdkInteractInterop = require('@monterosa/sdk-interact-interop');
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @license
|
|
11
|
+
* @monterosa/sdk-launcher-kit
|
|
12
|
+
*
|
|
13
|
+
* Copyright © 2022 Monterosa Productions Limited. All rights reserved.
|
|
14
|
+
*
|
|
15
|
+
* More details on the license can be found at https://www.monterosa.co/sdk/license
|
|
16
|
+
*/
|
|
17
|
+
const RESIZE_THROTTLE_TIMEOUT = 25;
|
|
18
|
+
/**
|
|
19
|
+
* Duration of the loader fade IN/OUT animation
|
|
20
|
+
*/
|
|
21
|
+
const LOADER_ANIMATION_DURATION = 750;
|
|
22
|
+
/**
|
|
23
|
+
* Final cut off timeout for the loader after which it will be hidden even
|
|
24
|
+
* though Experience UI may ne not yet ready
|
|
25
|
+
*/
|
|
26
|
+
const LOADER_TIMEOUT = 5000;
|
|
27
|
+
/**
|
|
28
|
+
* Bumper timeout during which the loader still visible even though Experience
|
|
29
|
+
* UI may be ready
|
|
30
|
+
*
|
|
31
|
+
* (!) At the moment its value is 0 as loader has a fade in effect what already
|
|
32
|
+
* adds a small bumper delay before Experience is injected on the page
|
|
33
|
+
*/
|
|
34
|
+
const LOADER_BUMPER_TIMEOUT = 0;
|
|
35
|
+
const DEFAULT_HEIGHT = 250;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* @license
|
|
39
|
+
* @monterosa/sdk-launcher-kit
|
|
40
|
+
*
|
|
41
|
+
* Copyright © 2023 Monterosa Productions Limited. All rights reserved.
|
|
42
|
+
*
|
|
43
|
+
* More details on the license can be found at https://www.monterosa.co/sdk/license
|
|
44
|
+
*/
|
|
45
|
+
const logger = new sdkCore.Logger('@monterosa/sdk-launcher-kit');
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* @license
|
|
49
|
+
* @monterosa/sdk-launcher-kit
|
|
50
|
+
*
|
|
51
|
+
* Copyright © 2022-2026 Monterosa Productions Limited. All rights reserved.
|
|
52
|
+
*
|
|
53
|
+
* More details on the license can be found at https://www.monterosa.co/sdk/license
|
|
54
|
+
*/
|
|
55
|
+
/**
|
|
56
|
+
* A list of possible actions in communications between
|
|
57
|
+
* parent application and child Experience
|
|
58
|
+
*
|
|
59
|
+
* @internal
|
|
60
|
+
*/
|
|
61
|
+
exports.Action = void 0;
|
|
62
|
+
(function (Action) {
|
|
63
|
+
/**
|
|
64
|
+
* Notifies that the Experience has initialised and is ready to receive messages.
|
|
65
|
+
* This also signals that the communication bridge is ready.
|
|
66
|
+
* This triggers the `initialised` lifecycle state.
|
|
67
|
+
*/
|
|
68
|
+
Action["OnInitialised"] = "onInitialised";
|
|
69
|
+
/**
|
|
70
|
+
* Notifies that UI of child Experience is loaded and ready to be visible.
|
|
71
|
+
* When this action is fired the loader will be hidden and
|
|
72
|
+
* the `ready` lifecycle state is triggered.
|
|
73
|
+
*/
|
|
74
|
+
Action["OnReady"] = "onReady";
|
|
75
|
+
/**
|
|
76
|
+
* Notifies that intrinsic size of child Experience has changed
|
|
77
|
+
*/
|
|
78
|
+
Action["OnResize"] = "onIntrinsicSizeChanged";
|
|
79
|
+
/**
|
|
80
|
+
* Notifies child Experience about the request to load more data
|
|
81
|
+
*/
|
|
82
|
+
Action["OnMoreDataRequested"] = "onMoreDataRequested";
|
|
83
|
+
/**
|
|
84
|
+
* Notifies about a share request
|
|
85
|
+
*/
|
|
86
|
+
Action["OnShare"] = "onShare";
|
|
87
|
+
})(exports.Action || (exports.Action = {}));
|
|
88
|
+
/**
|
|
89
|
+
* @internal
|
|
90
|
+
*/
|
|
91
|
+
exports.Source = void 0;
|
|
92
|
+
(function (Source) {
|
|
93
|
+
Source["Sdk"] = "sdk";
|
|
94
|
+
Source["User"] = "user";
|
|
95
|
+
})(exports.Source || (exports.Source = {}));
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* @license
|
|
99
|
+
* @monterosa/sdk-launcher-kit
|
|
100
|
+
*
|
|
101
|
+
* Copyright © 2022-2026 Monterosa Productions Limited. All rights reserved.
|
|
102
|
+
*
|
|
103
|
+
* More details on the license can be found at https://www.monterosa.co/sdk/license
|
|
104
|
+
*/
|
|
105
|
+
/**
|
|
106
|
+
* Reserved query parameter names for controlling the behaviour of Experience.
|
|
107
|
+
*/
|
|
108
|
+
exports.QueryParam = void 0;
|
|
109
|
+
(function (QueryParam) {
|
|
110
|
+
/**
|
|
111
|
+
* Represents the host of the application. This parameter is added by Studio
|
|
112
|
+
* and the embed URL already contains it.
|
|
113
|
+
*/
|
|
114
|
+
QueryParam["Host"] = "h";
|
|
115
|
+
/**
|
|
116
|
+
* Represents the Project ID of the application. This parameter is added by
|
|
117
|
+
* Studio and the embed URL already contains it.
|
|
118
|
+
*/
|
|
119
|
+
QueryParam["Project"] = "p";
|
|
120
|
+
/**
|
|
121
|
+
* Represents the Event ID of the application. This parameter is added to the
|
|
122
|
+
* Experience URL when the eventId is provided in the Experience config.
|
|
123
|
+
*/
|
|
124
|
+
QueryParam["Event"] = "e";
|
|
125
|
+
/**
|
|
126
|
+
* Used to identify the unique ID of the communication bridge between
|
|
127
|
+
* the parent application and the child experience.
|
|
128
|
+
*/
|
|
129
|
+
QueryParam["BridgeId"] = "micBridgeId";
|
|
130
|
+
/**
|
|
131
|
+
* Determines whether the header and footer views of the application should be
|
|
132
|
+
* hidden. This parameter can be used to control the visibility of the
|
|
133
|
+
* application's header and footer components.
|
|
134
|
+
*/
|
|
135
|
+
QueryParam["HideHeaderAndFooter"] = "micHideHeaderAndFooter";
|
|
136
|
+
/**
|
|
137
|
+
* Determines whether autoresize is enabled for the application. When autoresize
|
|
138
|
+
* is enabled, the application's height will adjust automatically based on its
|
|
139
|
+
* content.
|
|
140
|
+
*/
|
|
141
|
+
QueryParam["AutoresizesHeight"] = "micAutoresizesHeight";
|
|
142
|
+
})(exports.QueryParam || (exports.QueryParam = {}));
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* @license
|
|
146
|
+
* @monterosa/sdk-launcher-kit
|
|
147
|
+
*
|
|
148
|
+
* Copyright © 2024 Monterosa Productions Limited. All rights reserved.
|
|
149
|
+
*
|
|
150
|
+
* More details on the license can be found at https://www.monterosa.co/sdk/license
|
|
151
|
+
*/
|
|
152
|
+
/**
|
|
153
|
+
* Defines a set of error codes that may be encountered when using the
|
|
154
|
+
* Launcher Kit bridge
|
|
155
|
+
*
|
|
156
|
+
* @example
|
|
157
|
+
* ```javascript
|
|
158
|
+
* try {
|
|
159
|
+
* // some code that uses the LauncherKit's bridge
|
|
160
|
+
* } catch (err) {
|
|
161
|
+
* if (err.code === BridgeError.InvalidRequestTimeoutError) {
|
|
162
|
+
* // handle invalid request timeout error
|
|
163
|
+
* } else {
|
|
164
|
+
* // handle other error types
|
|
165
|
+
* }
|
|
166
|
+
* }
|
|
167
|
+
* ```
|
|
168
|
+
*
|
|
169
|
+
* @remarks
|
|
170
|
+
* - The `BridgeError` enum provides a convenient way to handle errors
|
|
171
|
+
* encountered when using the `LauncherKit` module. By checking the code
|
|
172
|
+
* property of the caught error against the values of the enum, the error
|
|
173
|
+
* type can be determined and appropriate action taken.
|
|
174
|
+
*
|
|
175
|
+
* - The `BridgeError` enum is not intended to be instantiated or extended.
|
|
176
|
+
*/
|
|
177
|
+
exports.BridgeError = void 0;
|
|
178
|
+
(function (BridgeError) {
|
|
179
|
+
/**
|
|
180
|
+
* Indicates an error occurred due to an invalid timeout value being provided.
|
|
181
|
+
* This error is thrown when the specified timeout is not a positive number.
|
|
182
|
+
*/
|
|
183
|
+
BridgeError["InvalidRequestTimeoutError"] = "invalid_request_timeout_error";
|
|
184
|
+
/**
|
|
185
|
+
* Indicates a request timed out waiting for a response.
|
|
186
|
+
* This error is thrown when a bridge request exceeds the specified timeout duration.
|
|
187
|
+
*/
|
|
188
|
+
BridgeError["RequestTimeoutError"] = "request_timeout_error";
|
|
189
|
+
})(exports.BridgeError || (exports.BridgeError = {}));
|
|
190
|
+
const BridgeErrorMessages = {
|
|
191
|
+
[exports.BridgeError.InvalidRequestTimeoutError]: () => 'Request timeout must be greater than 0',
|
|
192
|
+
[exports.BridgeError.RequestTimeoutError]: (action, timeout) => `Request timeout: action "${action}" did not receive a response within ${timeout}ms`,
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* @license
|
|
197
|
+
* @monterosa/sdk-launcher-kit
|
|
198
|
+
*
|
|
199
|
+
* Copyright © 2024 Monterosa Productions Limited. All rights reserved.
|
|
200
|
+
*
|
|
201
|
+
* More details on the license can be found at https://www.monterosa.co/sdk/license
|
|
202
|
+
*/
|
|
203
|
+
/**
|
|
204
|
+
* @internal
|
|
205
|
+
*/
|
|
206
|
+
const Config = {
|
|
207
|
+
requestTimeout: 20000,
|
|
208
|
+
};
|
|
209
|
+
/**
|
|
210
|
+
* Sets a new timeout value for requests (default is 20,000 ms).
|
|
211
|
+
*
|
|
212
|
+
* @remarks
|
|
213
|
+
* This function updates the request timeout in the application's configuration.
|
|
214
|
+
* It ensures that the new timeout value is a positive number, and throws
|
|
215
|
+
* an error if the value is non-positive.
|
|
216
|
+
*
|
|
217
|
+
* @param newTimeout - The new timeout value in milliseconds. Must be
|
|
218
|
+
* a positive number.
|
|
219
|
+
*
|
|
220
|
+
* @throws
|
|
221
|
+
* Throws {@link BridgeError | BridgeError.InvalidRequestTimeoutError}
|
|
222
|
+
* if `newTimeout` is less than or equal to 0.
|
|
223
|
+
*
|
|
224
|
+
* @example
|
|
225
|
+
* ```javascript
|
|
226
|
+
* // Set the request timeout to 3000 milliseconds
|
|
227
|
+
* setRequestTimeout(3000);
|
|
228
|
+
* ```
|
|
229
|
+
*/
|
|
230
|
+
function setRequestTimeout(newTimeout) {
|
|
231
|
+
if (newTimeout <= 0) {
|
|
232
|
+
throw sdkUtil.createError(exports.BridgeError.InvalidRequestTimeoutError, BridgeErrorMessages);
|
|
233
|
+
}
|
|
234
|
+
Config.requestTimeout = newTimeout;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* @license
|
|
239
|
+
* @monterosa/sdk-launcher-kit
|
|
240
|
+
*
|
|
241
|
+
* Copyright © 2022 Monterosa Productions Limited. All rights reserved.
|
|
242
|
+
*
|
|
243
|
+
* More details on the license can be found at https://www.monterosa.co/sdk/license
|
|
244
|
+
*/
|
|
245
|
+
function isMessage(message) {
|
|
246
|
+
return (message instanceof Object &&
|
|
247
|
+
Object.prototype.hasOwnProperty.call(message, 'bridgeId'));
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* @license
|
|
252
|
+
* @monterosa/sdk-launcher-kit
|
|
253
|
+
*
|
|
254
|
+
* Copyright © 2022 Monterosa Productions Limited. All rights reserved.
|
|
255
|
+
*
|
|
256
|
+
* More details on the license can be found at https://www.monterosa.co/sdk/license
|
|
257
|
+
*/
|
|
258
|
+
var _a$1, _b$1, _c$1, _d$1;
|
|
259
|
+
var _e, _f, _g;
|
|
260
|
+
const globals$2 = sdkUtil.getGlobal();
|
|
261
|
+
const receiveMessage = (message) => {
|
|
262
|
+
if (!isMessage(message)) {
|
|
263
|
+
// data does not match message format
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
globals$2.monterosaSdk.emitter.emit('message', message);
|
|
267
|
+
};
|
|
268
|
+
function handleWindowMessage({ data }) {
|
|
269
|
+
try {
|
|
270
|
+
if (typeof data !== 'string') {
|
|
271
|
+
// ignore non string data
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
const message = JSON.parse(data);
|
|
275
|
+
receiveMessage(message);
|
|
276
|
+
}
|
|
277
|
+
catch (err) {
|
|
278
|
+
console.error(sdkUtil.getErrorMessage(err));
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Since this code operates as a side effect while updating the global space,
|
|
283
|
+
* we must be very careful because it may run twice, for example, when two apps
|
|
284
|
+
* using the SDK run on the same page. Additionally, the global namespace may
|
|
285
|
+
* already be updated by the Android or iOS SDKs.
|
|
286
|
+
*/
|
|
287
|
+
// The Monterosa SDK namespace may already exist, either because it was created
|
|
288
|
+
// by a native SDK or by another web app using the JS SDK from the same scope.
|
|
289
|
+
(_a$1 = globals$2.monterosaSdk) !== null && _a$1 !== void 0 ? _a$1 : (globals$2.monterosaSdk = {
|
|
290
|
+
initialised: false,
|
|
291
|
+
emitter: new sdkUtil.Emitter(),
|
|
292
|
+
receiveMessage,
|
|
293
|
+
});
|
|
294
|
+
// Each of nullish coalescing assignments will only be applied when
|
|
295
|
+
// the Monterosa SDK namespace exists at that moment and one of its properties
|
|
296
|
+
// is not defined.
|
|
297
|
+
(_b$1 = (_e = globals$2.monterosaSdk).initialised) !== null && _b$1 !== void 0 ? _b$1 : (_e.initialised = false);
|
|
298
|
+
(_c$1 = (_f = globals$2.monterosaSdk).emitter) !== null && _c$1 !== void 0 ? _c$1 : (_f.emitter = new sdkUtil.Emitter());
|
|
299
|
+
(_d$1 = (_g = globals$2.monterosaSdk).receiveMessage) !== null && _d$1 !== void 0 ? _d$1 : (_g.receiveMessage = receiveMessage);
|
|
300
|
+
if (!globals$2.monterosaSdk.initialised) {
|
|
301
|
+
// Subscribe to the message only once for each app that uses the SDK on this page.
|
|
302
|
+
if (typeof globals$2.addEventListener !== 'undefined') {
|
|
303
|
+
globals$2.addEventListener('message', handleWindowMessage);
|
|
304
|
+
}
|
|
305
|
+
globals$2.monterosaSdk.initialised = true;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* @license
|
|
310
|
+
* @monterosa/sdk-launcher-kit
|
|
311
|
+
*
|
|
312
|
+
* Copyright © 2022 Monterosa Productions Limited. All rights reserved.
|
|
313
|
+
*
|
|
314
|
+
* More details on the license can be found at https://www.monterosa.co/sdk/license
|
|
315
|
+
*/
|
|
316
|
+
var _a, _b, _c, _d;
|
|
317
|
+
const globals$1 = sdkUtil.getGlobal();
|
|
318
|
+
/**
|
|
319
|
+
* @internal
|
|
320
|
+
*/
|
|
321
|
+
const IFRAME_ID_PREFIX = 'micBridge';
|
|
322
|
+
const IS_IOS = !!((_c = (_b = (_a = globals$1.webkit) === null || _a === void 0 ? void 0 : _a.messageHandlers) === null || _b === void 0 ? void 0 : _b.monterosaSdk) === null || _c === void 0 ? void 0 : _c.postMessage);
|
|
323
|
+
const IS_ANDROID = !!((_d = globals$1.monterosaSdk) === null || _d === void 0 ? void 0 : _d.postMessage);
|
|
324
|
+
const IS_WEB = globals$1.self !== globals$1.parent;
|
|
325
|
+
/**
|
|
326
|
+
* @internal
|
|
327
|
+
*/
|
|
328
|
+
const VERSION$1 = '1.0.0';
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* @license
|
|
332
|
+
* @monterosa/sdk-launcher-kit
|
|
333
|
+
*
|
|
334
|
+
* Copyright © 2022-2026 Monterosa Productions Limited. All rights reserved.
|
|
335
|
+
*
|
|
336
|
+
* More details on the license can be found at https://www.monterosa.co/sdk/license
|
|
337
|
+
*/
|
|
338
|
+
const globals = sdkUtil.getGlobal();
|
|
339
|
+
/**
|
|
340
|
+
* @internal
|
|
341
|
+
*/
|
|
342
|
+
class BridgeImpl extends sdkUtil.Emitter {
|
|
343
|
+
constructor(id = sdkUtil.generateUUID()) {
|
|
344
|
+
super();
|
|
345
|
+
this.id = id;
|
|
346
|
+
this.recipientInitialised = false;
|
|
347
|
+
this.messagesQueue = [];
|
|
348
|
+
globals.monterosaSdk.emitter.on('message', this.handleMessage.bind(this));
|
|
349
|
+
}
|
|
350
|
+
static isMessage(message) {
|
|
351
|
+
return (message instanceof Object &&
|
|
352
|
+
Object.prototype.hasOwnProperty.call(message, 'bridgeId') &&
|
|
353
|
+
Object.prototype.hasOwnProperty.call(message, 'action'));
|
|
354
|
+
}
|
|
355
|
+
get iFrameId() {
|
|
356
|
+
return `${IFRAME_ID_PREFIX}-${this.id}`;
|
|
357
|
+
}
|
|
358
|
+
get iFrameSelector() {
|
|
359
|
+
return `iframe#${this.iFrameId}`;
|
|
360
|
+
}
|
|
361
|
+
get childIFrame() {
|
|
362
|
+
return document.querySelector(this.iFrameSelector);
|
|
363
|
+
}
|
|
364
|
+
handleMessage(message) {
|
|
365
|
+
const { id, bridgeId, action, respondingTo } = message;
|
|
366
|
+
if (bridgeId !== this.id) {
|
|
367
|
+
return;
|
|
368
|
+
}
|
|
369
|
+
logger.log(`Received a ${respondingTo === null ? 'message' : 'response'}`, message);
|
|
370
|
+
if (action === exports.Action.OnInitialised) {
|
|
371
|
+
this.recipientInitialised = true;
|
|
372
|
+
if (respondingTo === null) {
|
|
373
|
+
this.send(exports.Action.OnInitialised, {}, exports.Source.Sdk, id);
|
|
374
|
+
}
|
|
375
|
+
while (this.messagesQueue.length > 0) {
|
|
376
|
+
this.postMessage(this.messagesQueue.shift());
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
this.emit('message', message);
|
|
380
|
+
}
|
|
381
|
+
createMessage(action, payload, sourceName, respondingTo = null) {
|
|
382
|
+
return {
|
|
383
|
+
id: sdkUtil.generateUUID(),
|
|
384
|
+
respondingTo,
|
|
385
|
+
action,
|
|
386
|
+
sourceName,
|
|
387
|
+
bridgeId: this.id,
|
|
388
|
+
payload,
|
|
389
|
+
version: VERSION$1,
|
|
390
|
+
timestamp: Date.now(),
|
|
391
|
+
};
|
|
392
|
+
}
|
|
393
|
+
postMessage(message) {
|
|
394
|
+
var _a, _b, _c, _d;
|
|
395
|
+
if (!this.recipientInitialised && message.action !== exports.Action.OnInitialised) {
|
|
396
|
+
this.messagesQueue.push(message);
|
|
397
|
+
return;
|
|
398
|
+
}
|
|
399
|
+
const json = JSON.stringify(message);
|
|
400
|
+
if (IS_IOS) {
|
|
401
|
+
(_b = (_a = globals.webkit) === null || _a === void 0 ? void 0 : _a.messageHandlers) === null || _b === void 0 ? void 0 : _b.monterosaSdk.postMessage(json);
|
|
402
|
+
}
|
|
403
|
+
if (IS_ANDROID) {
|
|
404
|
+
if ((_c = globals.monterosaSdk) === null || _c === void 0 ? void 0 : _c.postMessage) {
|
|
405
|
+
globals.monterosaSdk.postMessage(json);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
if (IS_WEB) {
|
|
409
|
+
globals.parent.postMessage(json, '*');
|
|
410
|
+
}
|
|
411
|
+
if (this.childIFrame) {
|
|
412
|
+
(_d = this.childIFrame.contentWindow) === null || _d === void 0 ? void 0 : _d.postMessage(json, '*');
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
send(action, payload = {}, sourceName = exports.Source.Sdk, respondingTo) {
|
|
416
|
+
const message = this.createMessage(action, payload, sourceName, respondingTo);
|
|
417
|
+
logger.log(`Sending a ${message.respondingTo === null ? 'message' : 'response'}`, message);
|
|
418
|
+
this.postMessage(message);
|
|
419
|
+
return message;
|
|
420
|
+
}
|
|
421
|
+
async request(action, payload = {}, timeout = Config.requestTimeout, sourceName = exports.Source.Sdk) {
|
|
422
|
+
let timeoutRef;
|
|
423
|
+
let handler;
|
|
424
|
+
const message = this.createMessage(action, payload, sourceName);
|
|
425
|
+
logger.log('Sending a request', message);
|
|
426
|
+
/**
|
|
427
|
+
* Start the timeout, when it finishes it should reject Promise.race below
|
|
428
|
+
*/
|
|
429
|
+
const countdown = new Promise((_, reject) => {
|
|
430
|
+
timeoutRef = setTimeout(() => {
|
|
431
|
+
reject(sdkUtil.createError(exports.BridgeError.RequestTimeoutError, BridgeErrorMessages, action, timeout));
|
|
432
|
+
}, timeout);
|
|
433
|
+
});
|
|
434
|
+
/**
|
|
435
|
+
* Start the request and wait for the message with the respondingTo
|
|
436
|
+
* equal to message id we sent
|
|
437
|
+
*/
|
|
438
|
+
const request = new Promise((resolve) => {
|
|
439
|
+
handler = (responseMessage) => {
|
|
440
|
+
if (responseMessage.respondingTo === message.id) {
|
|
441
|
+
resolve(responseMessage);
|
|
442
|
+
}
|
|
443
|
+
};
|
|
444
|
+
globals.monterosaSdk.emitter.on('message', handler);
|
|
445
|
+
this.postMessage(message);
|
|
446
|
+
});
|
|
447
|
+
/**
|
|
448
|
+
* Start race between timeout and request
|
|
449
|
+
* - if timeout wins the promise will be rejected
|
|
450
|
+
* - if request wins then Message will be resolved
|
|
451
|
+
*/
|
|
452
|
+
return (Promise.race([countdown, request])
|
|
453
|
+
/**
|
|
454
|
+
* As the matter of clean up we need to clear timeout id
|
|
455
|
+
* and unsubscribe from the message event
|
|
456
|
+
*/
|
|
457
|
+
.finally(() => {
|
|
458
|
+
clearTimeout(timeoutRef);
|
|
459
|
+
globals.monterosaSdk.emitter.off('message', handler);
|
|
460
|
+
}));
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
/**
|
|
465
|
+
* @license
|
|
466
|
+
* @monterosa/sdk-launcher-kit
|
|
467
|
+
*
|
|
468
|
+
* Copyright © 2022-2026 Monterosa Productions Limited. All rights reserved.
|
|
469
|
+
*
|
|
470
|
+
* More details on the license can be found at https://www.monterosa.co/sdk/license
|
|
471
|
+
*/
|
|
472
|
+
let parentBridge;
|
|
473
|
+
const bridges = new Map();
|
|
474
|
+
/**
|
|
475
|
+
* @internal
|
|
476
|
+
*/
|
|
477
|
+
function getBridge(id) {
|
|
478
|
+
if (bridges.has(id)) {
|
|
479
|
+
return bridges.get(id);
|
|
480
|
+
}
|
|
481
|
+
const bridge = new BridgeImpl(id);
|
|
482
|
+
bridges.set(id, bridge);
|
|
483
|
+
return bridge;
|
|
484
|
+
}
|
|
485
|
+
/**
|
|
486
|
+
* Returns true if the page is inside an iframe.
|
|
487
|
+
*
|
|
488
|
+
* @internal
|
|
489
|
+
*/
|
|
490
|
+
function isInsideIframe() {
|
|
491
|
+
if (typeof window === 'undefined') {
|
|
492
|
+
return false;
|
|
493
|
+
}
|
|
494
|
+
try {
|
|
495
|
+
return window.self !== window.top;
|
|
496
|
+
}
|
|
497
|
+
catch (_a) {
|
|
498
|
+
// SecurityError is thrown when accessing window.top in a cross-origin iframe.
|
|
499
|
+
// If we can't access it, we're definitely in an iframe.
|
|
500
|
+
return true;
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
/**
|
|
504
|
+
* @internal
|
|
505
|
+
*/
|
|
506
|
+
function getParentBridge() {
|
|
507
|
+
if (typeof window === 'undefined') {
|
|
508
|
+
return null;
|
|
509
|
+
}
|
|
510
|
+
if (parentBridge !== undefined) {
|
|
511
|
+
return parentBridge;
|
|
512
|
+
}
|
|
513
|
+
if (!isInsideIframe()) {
|
|
514
|
+
return null;
|
|
515
|
+
}
|
|
516
|
+
const url = new URL(window.location.href);
|
|
517
|
+
const bridgeId = url.searchParams.get(exports.QueryParam.BridgeId);
|
|
518
|
+
if (bridgeId === null) {
|
|
519
|
+
return null;
|
|
520
|
+
}
|
|
521
|
+
parentBridge = new BridgeImpl(bridgeId);
|
|
522
|
+
return parentBridge;
|
|
523
|
+
}
|
|
524
|
+
/**
|
|
525
|
+
* @internal
|
|
526
|
+
*/
|
|
527
|
+
function sendSdkMessage(bridged, action, payload = {}) {
|
|
528
|
+
return bridged.bridge.send(action, payload, exports.Source.Sdk);
|
|
529
|
+
}
|
|
530
|
+
/**
|
|
531
|
+
* Sends a message with an action name and payload to a parent application or child Experience.
|
|
532
|
+
*
|
|
533
|
+
* @remarks
|
|
534
|
+
* Usage example in parent application:
|
|
535
|
+
*
|
|
536
|
+
* @example
|
|
537
|
+
* ```typescript
|
|
538
|
+
* const experience = getExperience();
|
|
539
|
+
*
|
|
540
|
+
* // message to Experience can be sent only when its initialised
|
|
541
|
+
* onStateChanged(experience, (state) => {
|
|
542
|
+
* if (state === 'initialised') {
|
|
543
|
+
* sendMessage(
|
|
544
|
+
* experience,
|
|
545
|
+
* 'my_action',
|
|
546
|
+
* { key: 'value' }
|
|
547
|
+
* );
|
|
548
|
+
* }
|
|
549
|
+
* });
|
|
550
|
+
*
|
|
551
|
+
* embed(experience);
|
|
552
|
+
* ```
|
|
553
|
+
*
|
|
554
|
+
* Usage example in child Experience:
|
|
555
|
+
*
|
|
556
|
+
* @example
|
|
557
|
+
* ```typescript
|
|
558
|
+
* const parentApp = getParentApplication();
|
|
559
|
+
*
|
|
560
|
+
* if (parentApp !== null) {
|
|
561
|
+
* sendMessage(
|
|
562
|
+
* parentApp,
|
|
563
|
+
* 'my_action',
|
|
564
|
+
* { key: 'value' }
|
|
565
|
+
* );
|
|
566
|
+
* }
|
|
567
|
+
* ```
|
|
568
|
+
*
|
|
569
|
+
* @param bridged - Instance of either {@link ParentApplication} or {@link Experience}
|
|
570
|
+
* @param action - Arbitrary action name that defines purpose of the message
|
|
571
|
+
* @param payload - A key-value object that is sent in a message
|
|
572
|
+
* @returns Returns {@link Message | message}
|
|
573
|
+
*/
|
|
574
|
+
function sendMessage(bridged, action, payload = {}) {
|
|
575
|
+
return bridged.bridge.send(action, payload, exports.Source.User);
|
|
576
|
+
}
|
|
577
|
+
/**
|
|
578
|
+
* @internal
|
|
579
|
+
*/
|
|
580
|
+
function sendSdkRequest(bridged, action, payload = {}, timeout = Config.requestTimeout) {
|
|
581
|
+
return bridged.bridge.request(action, payload, timeout, exports.Source.Sdk);
|
|
582
|
+
}
|
|
583
|
+
/**
|
|
584
|
+
* Sends a request and returns a Promise that resolves when the recipient responds.
|
|
585
|
+
*
|
|
586
|
+
* @remarks
|
|
587
|
+
* Similar to {@link sendMessage} but returns a Promise which
|
|
588
|
+
* resolves if the recipient responds with {@link respondToMessage}. Otherwise it
|
|
589
|
+
* rejects after a certain timeout.
|
|
590
|
+
*
|
|
591
|
+
* Usage example in parent application:
|
|
592
|
+
*
|
|
593
|
+
* @example
|
|
594
|
+
* ```typescript
|
|
595
|
+
* const experience = getExperience();
|
|
596
|
+
*
|
|
597
|
+
* // request to Experience can be sent only when its initialised
|
|
598
|
+
* onStateChanged(experience, async (state) => {
|
|
599
|
+
* if (state === 'initialised') {
|
|
600
|
+
* const response = await sendRequest(
|
|
601
|
+
* experience,
|
|
602
|
+
* 'my_action',
|
|
603
|
+
* { key: 'value' }
|
|
604
|
+
* );
|
|
605
|
+
*
|
|
606
|
+
* console.log(response);
|
|
607
|
+
* }
|
|
608
|
+
* });
|
|
609
|
+
*
|
|
610
|
+
* embed(experience);
|
|
611
|
+
* ```
|
|
612
|
+
*
|
|
613
|
+
* Usage example in child Experience:
|
|
614
|
+
*
|
|
615
|
+
* @example
|
|
616
|
+
* ```typescript
|
|
617
|
+
* const parentApp = getParentApplication();
|
|
618
|
+
*
|
|
619
|
+
* // parent application can be null if Experience is running stand alone
|
|
620
|
+
* if (parentApp !== null) {
|
|
621
|
+
* const response = await sendRequest(
|
|
622
|
+
* parentApp,
|
|
623
|
+
* 'my_action',
|
|
624
|
+
* { key: 'value' }
|
|
625
|
+
* );
|
|
626
|
+
*
|
|
627
|
+
* console.log(response);
|
|
628
|
+
* }
|
|
629
|
+
* ```
|
|
630
|
+
*
|
|
631
|
+
* @param bridged - Instance of either {@link ParentApplication} or {@link Experience}
|
|
632
|
+
* @param action - Arbitrary action name that defines purpose of the message
|
|
633
|
+
* @param payload - A key-value object that is sent as in request
|
|
634
|
+
* @param timeout - Configurable request timeout, if there is no response by
|
|
635
|
+
* the end of this timeout then returned Promise will be rejected.
|
|
636
|
+
*/
|
|
637
|
+
function sendRequest(bridged, action, payload = {}, timeout = Config.requestTimeout) {
|
|
638
|
+
return bridged.bridge.request(action, payload, timeout, exports.Source.User);
|
|
639
|
+
}
|
|
640
|
+
/**
|
|
641
|
+
* @internal
|
|
642
|
+
*/
|
|
643
|
+
function respondToSdkMessage(bridged, message, payload = {}) {
|
|
644
|
+
bridged.bridge.send(message.action, payload, exports.Source.Sdk, message.id);
|
|
645
|
+
}
|
|
646
|
+
/**
|
|
647
|
+
* Respond to a received message. It is used to reply to a
|
|
648
|
+
* {@link sendRequest | user request}.
|
|
649
|
+
*
|
|
650
|
+
* @param bridged - Instance of either {@link ParentApplication} or {@link Experience}
|
|
651
|
+
* @param message - {@link Message | Message} to respond to
|
|
652
|
+
* @param payload - A key-value object that is sent as in response
|
|
653
|
+
*/
|
|
654
|
+
function respondToMessage(bridged, message, payload = {}) {
|
|
655
|
+
bridged.bridge.send(message.action, payload, exports.Source.User, message.id);
|
|
656
|
+
}
|
|
657
|
+
function onMessageFunc(bridged, source, callback) {
|
|
658
|
+
return sdkUtil.subscribe(bridged.bridge, 'message', (message) => {
|
|
659
|
+
if (message.sourceName === source) {
|
|
660
|
+
callback(message);
|
|
661
|
+
}
|
|
662
|
+
});
|
|
663
|
+
}
|
|
664
|
+
/**
|
|
665
|
+
* @internal
|
|
666
|
+
*/
|
|
667
|
+
function onSdkMessage(bridged, callback) {
|
|
668
|
+
return onMessageFunc(bridged, exports.Source.Sdk, callback);
|
|
669
|
+
}
|
|
670
|
+
/**
|
|
671
|
+
* @internal
|
|
672
|
+
*
|
|
673
|
+
* Adds an observer for when user message is received
|
|
674
|
+
*
|
|
675
|
+
* @param bridged - Instance of either {@link ParentApplication} or {@link Experience}
|
|
676
|
+
* @param callback - The callback that is triggered when user message is received
|
|
677
|
+
* @returns The unsubscribe function. When it's called,
|
|
678
|
+
* the observer will be removed and user messages will no longer be received
|
|
679
|
+
*/
|
|
680
|
+
function onMessage(bridged, callback) {
|
|
681
|
+
return onMessageFunc(bridged, exports.Source.User, callback);
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
/**
|
|
685
|
+
* @license
|
|
686
|
+
* @monterosa/sdk-launcher-kit
|
|
687
|
+
*
|
|
688
|
+
* Copyright © 2022-2026 Monterosa Productions Limited. All rights reserved.
|
|
689
|
+
*
|
|
690
|
+
* More details on the license can be found at https://www.monterosa.co/sdk/license
|
|
691
|
+
*/
|
|
692
|
+
/**
|
|
693
|
+
* @internal
|
|
694
|
+
*/
|
|
695
|
+
class ExperienceImpl {
|
|
696
|
+
constructor(sdk, config) {
|
|
697
|
+
this.sdk = sdk;
|
|
698
|
+
this._parameters = {};
|
|
699
|
+
this.id = sdkUtil.generateUUID();
|
|
700
|
+
this.state = 'unmounted';
|
|
701
|
+
this.customElement = null;
|
|
702
|
+
this._config = config;
|
|
703
|
+
this.bridge = getBridge(this.id);
|
|
704
|
+
if (config.parameters !== undefined) {
|
|
705
|
+
const reserved = Object.values(exports.QueryParam);
|
|
706
|
+
const ignored = [];
|
|
707
|
+
Object.entries(config.parameters).forEach(([key, value]) => {
|
|
708
|
+
if (reserved.includes(key)) {
|
|
709
|
+
ignored.push(key);
|
|
710
|
+
}
|
|
711
|
+
else {
|
|
712
|
+
this._parameters[key] = value;
|
|
713
|
+
}
|
|
714
|
+
});
|
|
715
|
+
if (ignored.length === 1) {
|
|
716
|
+
console.warn(`Parameter "${ignored[0]}" ignored as it matches reserved words`);
|
|
717
|
+
}
|
|
718
|
+
if (ignored.length > 1) {
|
|
719
|
+
console.warn(`Parameters "${ignored.join('", "')}" ignored as they match reserved words`);
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
get config() {
|
|
724
|
+
var _a, _b, _c, _d;
|
|
725
|
+
return Object.assign(this._config, {
|
|
726
|
+
autoresizesHeight: (_a = this._config.autoresizesHeight) !== null && _a !== void 0 ? _a : false,
|
|
727
|
+
hidesHeadersAndFooters: (_b = this._config.hidesHeadersAndFooters) !== null && _b !== void 0 ? _b : true,
|
|
728
|
+
supportsLoadingState: (_c = this._config.supportsLoadingState) !== null && _c !== void 0 ? _c : true,
|
|
729
|
+
experienceUrl: (_d = this._config.experienceUrl) !== null && _d !== void 0 ? _d : null,
|
|
730
|
+
});
|
|
731
|
+
}
|
|
732
|
+
async getEmbedUrl() {
|
|
733
|
+
if (this.embedUrl) {
|
|
734
|
+
return Promise.resolve(this.embedUrl);
|
|
735
|
+
}
|
|
736
|
+
const { options: { host, projectId }, } = this.sdk;
|
|
737
|
+
const listings = await sdkInteractInterop.fetchListings(host, projectId);
|
|
738
|
+
this.embedUrl = listings.project.embed;
|
|
739
|
+
return this.embedUrl;
|
|
740
|
+
}
|
|
741
|
+
async getUrl() {
|
|
742
|
+
const embedUrl = await this.getEmbedUrl();
|
|
743
|
+
// sanitise and create an object from an url
|
|
744
|
+
let url = new URL(ExperienceImpl.sanitiseUrl(embedUrl));
|
|
745
|
+
// override host and project with those that are set in SDK instance
|
|
746
|
+
url.searchParams.set(exports.QueryParam.Host, this.sdk.options.host);
|
|
747
|
+
url.searchParams.set(exports.QueryParam.Project, this.sdk.options.projectId);
|
|
748
|
+
// if custom experienceUrl is set:
|
|
749
|
+
// * take experienceUrl as the base
|
|
750
|
+
// * search params from experienceUrl have priority
|
|
751
|
+
if (this.config.experienceUrl !== null) {
|
|
752
|
+
// sanitise and create an object from a custom url
|
|
753
|
+
const customUrl = new URL(ExperienceImpl.sanitiseUrl(this.config.experienceUrl));
|
|
754
|
+
// apply embedUrl query parameters if they don't exist in experienceUrl
|
|
755
|
+
Array.from(url.searchParams.entries())
|
|
756
|
+
.filter(([key]) => !customUrl.searchParams.has(key))
|
|
757
|
+
.forEach(([key, value]) => customUrl.searchParams.set(key, value));
|
|
758
|
+
url = customUrl;
|
|
759
|
+
}
|
|
760
|
+
// Prepare a final list of query parameters
|
|
761
|
+
const queryParameters = Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, (this.config.host !== undefined && {
|
|
762
|
+
[exports.QueryParam.Host]: this.config.host,
|
|
763
|
+
})), (this.config.projectId !== undefined && {
|
|
764
|
+
[exports.QueryParam.Project]: this.config.projectId,
|
|
765
|
+
})), (this.config.eventId !== undefined && {
|
|
766
|
+
[exports.QueryParam.Event]: this.config.eventId,
|
|
767
|
+
})), { [exports.QueryParam.BridgeId]: this.bridge.id, [exports.QueryParam.HideHeaderAndFooter]: this.config.hidesHeadersAndFooters
|
|
768
|
+
? '1'
|
|
769
|
+
: '0', [exports.QueryParam.AutoresizesHeight]: this.config.autoresizesHeight ? '1' : '0' }), this._parameters);
|
|
770
|
+
Object.entries(queryParameters).forEach(([key, value]) => {
|
|
771
|
+
url.searchParams.set(key, value);
|
|
772
|
+
});
|
|
773
|
+
return url.href;
|
|
774
|
+
}
|
|
775
|
+
static sanitiseUrl(url, options) {
|
|
776
|
+
const stripReservedParameters = (options === null || options === void 0 ? void 0 : options.stripReservedParameters) || 'mic';
|
|
777
|
+
// Ensure the URL includes a protocol.
|
|
778
|
+
if (/^http/.test(url) === false) {
|
|
779
|
+
// If none are found, use the same as the document.
|
|
780
|
+
url = `${document.location.protocol}${url}`;
|
|
781
|
+
}
|
|
782
|
+
const urlObj = new URL(url);
|
|
783
|
+
Object.values(exports.QueryParam)
|
|
784
|
+
.filter((key) => {
|
|
785
|
+
if (stripReservedParameters === 'mic') {
|
|
786
|
+
return key.startsWith('mic');
|
|
787
|
+
}
|
|
788
|
+
return key;
|
|
789
|
+
})
|
|
790
|
+
.forEach((key) => urlObj.searchParams.delete(key));
|
|
791
|
+
return urlObj.href;
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
/**
|
|
796
|
+
* @license
|
|
797
|
+
* @monterosa/sdk-launcher-kit
|
|
798
|
+
*
|
|
799
|
+
* Copyright © 2025-2026 Monterosa Productions Limited. All rights reserved.
|
|
800
|
+
*
|
|
801
|
+
* More details on the license can be found at https://www.monterosa.co/sdk/license
|
|
802
|
+
*/
|
|
803
|
+
const integrations = new Map();
|
|
804
|
+
function addIntegration(container, integration) {
|
|
805
|
+
integrations.set(container, integration);
|
|
806
|
+
}
|
|
807
|
+
function getIntegration(containerOrExperience) {
|
|
808
|
+
if (containerOrExperience instanceof HTMLElement) {
|
|
809
|
+
return integrations.get(containerOrExperience);
|
|
810
|
+
}
|
|
811
|
+
return Array.from(integrations.values()).find((integration) => integration.experience === containerOrExperience);
|
|
812
|
+
}
|
|
813
|
+
function deleteIntegration(container) {
|
|
814
|
+
integrations.delete(container);
|
|
815
|
+
}
|
|
816
|
+
function hasIntegration(containerOrExperience) {
|
|
817
|
+
if (containerOrExperience instanceof HTMLElement) {
|
|
818
|
+
return integrations.has(containerOrExperience);
|
|
819
|
+
}
|
|
820
|
+
return Array.from(integrations.values()).some((integration) => integration.experience === containerOrExperience);
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
/**
|
|
824
|
+
* @license
|
|
825
|
+
* @monterosa/sdk-launcher-kit
|
|
826
|
+
*
|
|
827
|
+
* Copyright © 2026 Monterosa Productions Limited. All rights reserved.
|
|
828
|
+
*
|
|
829
|
+
* More details on the license can be found at https://www.monterosa.co/sdk/license
|
|
830
|
+
*/
|
|
831
|
+
/**
|
|
832
|
+
* Event emitter for Experience state changes.
|
|
833
|
+
*
|
|
834
|
+
* @internal
|
|
835
|
+
*/
|
|
836
|
+
const stateEmitter = new sdkUtil.Emitter();
|
|
837
|
+
/**
|
|
838
|
+
* Updates the Experience state and emits a state change event.
|
|
839
|
+
*
|
|
840
|
+
* @param experience - The Experience instance to update
|
|
841
|
+
* @param newState - The target state to transition to
|
|
842
|
+
*
|
|
843
|
+
* @internal
|
|
844
|
+
*/
|
|
845
|
+
function updateExperienceState(experience, newState) {
|
|
846
|
+
const currentState = experience.state;
|
|
847
|
+
// No-op if already in the target state
|
|
848
|
+
if (currentState === newState) {
|
|
849
|
+
return;
|
|
850
|
+
}
|
|
851
|
+
// Cast to ExperienceImpl to access the mutable state property
|
|
852
|
+
experience.state = newState;
|
|
853
|
+
stateEmitter.emit('stateChanged', experience, newState);
|
|
854
|
+
}
|
|
855
|
+
function onStateChanged(experienceOrCallback, callback) {
|
|
856
|
+
if (typeof experienceOrCallback === 'function') {
|
|
857
|
+
// Global handler: onStateChanged(callback)
|
|
858
|
+
const globalCallback = experienceOrCallback;
|
|
859
|
+
stateEmitter.on('stateChanged', globalCallback);
|
|
860
|
+
return () => {
|
|
861
|
+
stateEmitter.off('stateChanged', globalCallback);
|
|
862
|
+
};
|
|
863
|
+
}
|
|
864
|
+
// Instance handler: onStateChanged(experience, callback)
|
|
865
|
+
const experience = experienceOrCallback;
|
|
866
|
+
const instanceCallback = callback;
|
|
867
|
+
const wrappedCallback = (exp, state) => {
|
|
868
|
+
if (exp === experience) {
|
|
869
|
+
instanceCallback(state);
|
|
870
|
+
}
|
|
871
|
+
};
|
|
872
|
+
stateEmitter.on('stateChanged', wrappedCallback);
|
|
873
|
+
return () => {
|
|
874
|
+
stateEmitter.off('stateChanged', wrappedCallback);
|
|
875
|
+
};
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
/**
|
|
879
|
+
* @license
|
|
880
|
+
* @monterosa/sdk-launcher-kit
|
|
881
|
+
*
|
|
882
|
+
* Copyright © 2022 Monterosa Productions Limited. All rights reserved.
|
|
883
|
+
*
|
|
884
|
+
* More details on the license can be found at https://www.monterosa.co/sdk/license
|
|
885
|
+
*/
|
|
886
|
+
/* eslint-enable */
|
|
887
|
+
function getLoadingTemplate() {
|
|
888
|
+
return `
|
|
889
|
+
<div>
|
|
890
|
+
<style type="text/css">
|
|
891
|
+
.__mic-loader {
|
|
892
|
+
position: absolute;
|
|
893
|
+
width: 100%;
|
|
894
|
+
height: 100%;
|
|
895
|
+
z-index: 9;
|
|
896
|
+
box-sizing: border-box;
|
|
897
|
+
text-align: center;
|
|
898
|
+
background: #fff;
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
.__mic-loader__container {
|
|
902
|
+
padding: 20px 0;
|
|
903
|
+
gap: 20px;
|
|
904
|
+
min-height: ${DEFAULT_HEIGHT}px;
|
|
905
|
+
display: flex;
|
|
906
|
+
flex-direction: column;
|
|
907
|
+
justify-content: center;
|
|
908
|
+
align-items: center;
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
.__mic-loader__spinner {
|
|
912
|
+
position: relative;
|
|
913
|
+
width: 10px;
|
|
914
|
+
height: 10px;
|
|
915
|
+
border-radius: 5px;
|
|
916
|
+
background-color: #0b0f1c;
|
|
917
|
+
color: #0b0f1c;
|
|
918
|
+
animation: mic-loader__animation 1s infinite linear alternate;
|
|
919
|
+
animation-delay: 0.5s;
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
.__mic-loader__spinner::before,
|
|
923
|
+
.__mic-loader__spinner::after {
|
|
924
|
+
content: "";
|
|
925
|
+
display: inline-block;
|
|
926
|
+
position: absolute;
|
|
927
|
+
top: 0;
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
.__mic-loader__spinner::before {
|
|
931
|
+
left: -15px;
|
|
932
|
+
width: 10px;
|
|
933
|
+
height: 10px;
|
|
934
|
+
border-radius: 5px;
|
|
935
|
+
background-color: #0b0f1c;
|
|
936
|
+
color: #0b0f1c;
|
|
937
|
+
animation: mic-loader__animation 1s infinite alternate;
|
|
938
|
+
animation-delay: 0s;
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
.__mic-loader__spinner::after {
|
|
942
|
+
left: 15px;
|
|
943
|
+
width: 10px;
|
|
944
|
+
height: 10px;
|
|
945
|
+
border-radius: 5px;
|
|
946
|
+
background-color: #0b0f1c;
|
|
947
|
+
color: #0b0f1c;
|
|
948
|
+
animation: mic-loader__animation 1s infinite alternate;
|
|
949
|
+
animation-delay: 1s;
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
@keyframes mic-loader__animation {
|
|
953
|
+
0% {
|
|
954
|
+
background-color: #0b0f1c;
|
|
955
|
+
}
|
|
956
|
+
50%, 100% {
|
|
957
|
+
background-color: rgba(11, 15, 28, 0.2);
|
|
958
|
+
}
|
|
959
|
+
}
|
|
960
|
+
</style>
|
|
961
|
+
<div class="__mic-loader">
|
|
962
|
+
<div class="__mic-loader__container">
|
|
963
|
+
<div class="__mic-loader__spinner"></div>
|
|
964
|
+
</div>
|
|
965
|
+
</div>
|
|
966
|
+
</div>
|
|
967
|
+
`;
|
|
968
|
+
}
|
|
969
|
+
function embed$1(container, loadingTemplate = getLoadingTemplate) {
|
|
970
|
+
/**
|
|
971
|
+
* Return existing element if it exists
|
|
972
|
+
*/
|
|
973
|
+
let loaderElement = container.querySelector('[data-role=loader]');
|
|
974
|
+
if (loaderElement !== null) {
|
|
975
|
+
return loaderElement;
|
|
976
|
+
}
|
|
977
|
+
/**
|
|
978
|
+
* Stash and apply some custom styles to container element
|
|
979
|
+
*/
|
|
980
|
+
stashStyles(container, ['minHeight', 'position']);
|
|
981
|
+
container.style.minHeight = `${DEFAULT_HEIGHT}px`;
|
|
982
|
+
/**
|
|
983
|
+
* Inject loader element built from the html markup template
|
|
984
|
+
*/
|
|
985
|
+
const templateElement = document.createElement('template');
|
|
986
|
+
templateElement.innerHTML = loadingTemplate().trim();
|
|
987
|
+
loaderElement = container.appendChild(templateElement.content.firstElementChild);
|
|
988
|
+
/**
|
|
989
|
+
* Setting custom data attribute to be able to distinguish element along
|
|
990
|
+
* other injected html elements if any
|
|
991
|
+
*/
|
|
992
|
+
loaderElement.setAttribute('data-role', 'loader');
|
|
993
|
+
return loaderElement;
|
|
994
|
+
}
|
|
995
|
+
function unmount$1(container) {
|
|
996
|
+
var _a;
|
|
997
|
+
const loaderElement = container.querySelector('[data-role=loader]');
|
|
998
|
+
if (loaderElement === null) {
|
|
999
|
+
return;
|
|
1000
|
+
}
|
|
1001
|
+
(_a = loaderElement.parentElement) === null || _a === void 0 ? void 0 : _a.removeChild(loaderElement);
|
|
1002
|
+
unstashStyles(container);
|
|
1003
|
+
}
|
|
1004
|
+
async function show(container, loadingTemplate = getLoadingTemplate) {
|
|
1005
|
+
const loaderElement = embed$1(container, loadingTemplate);
|
|
1006
|
+
const { position } = getComputedStyle(container);
|
|
1007
|
+
/**
|
|
1008
|
+
* In order to properly position the loader,
|
|
1009
|
+
* the container's position should be anything but 'static'.
|
|
1010
|
+
*/
|
|
1011
|
+
if (position === 'static') {
|
|
1012
|
+
container.style.position = 'relative';
|
|
1013
|
+
}
|
|
1014
|
+
/**
|
|
1015
|
+
* Setting styles to the loader for a nice fade in animation
|
|
1016
|
+
*/
|
|
1017
|
+
loaderElement.style.opacity = '0';
|
|
1018
|
+
/**
|
|
1019
|
+
* Kicking fade animation in.
|
|
1020
|
+
*/
|
|
1021
|
+
setTimeout(() => {
|
|
1022
|
+
loaderElement.style.transition = `all ${LOADER_ANIMATION_DURATION}ms`;
|
|
1023
|
+
loaderElement.style.opacity = '1';
|
|
1024
|
+
}, 0);
|
|
1025
|
+
/**
|
|
1026
|
+
* Wait until the animation is finished. We do not use "transitionend" event
|
|
1027
|
+
* here as it will just make the code more bloated and unnecessary complex.
|
|
1028
|
+
*/
|
|
1029
|
+
await sdkUtil.delay(LOADER_ANIMATION_DURATION);
|
|
1030
|
+
}
|
|
1031
|
+
async function hide(container) {
|
|
1032
|
+
const loaderElement = container.querySelector('[data-role=loader]');
|
|
1033
|
+
if (loaderElement === null) {
|
|
1034
|
+
return;
|
|
1035
|
+
}
|
|
1036
|
+
/**
|
|
1037
|
+
* Kicking fade out animation.
|
|
1038
|
+
*/
|
|
1039
|
+
setTimeout(() => {
|
|
1040
|
+
loaderElement.style.opacity = '0';
|
|
1041
|
+
}, 0);
|
|
1042
|
+
/**
|
|
1043
|
+
* Wait until the animation is finished. We do not use "transitionend" event
|
|
1044
|
+
* here as it will just make the code more bloated and unnecessary complex.
|
|
1045
|
+
*/
|
|
1046
|
+
await sdkUtil.delay(LOADER_ANIMATION_DURATION);
|
|
1047
|
+
unstashStyles(container);
|
|
1048
|
+
unmount$1(container);
|
|
1049
|
+
}
|
|
1050
|
+
function stashStyles(element, props) {
|
|
1051
|
+
const styles = getComputedStyle(element);
|
|
1052
|
+
const stash = props
|
|
1053
|
+
.map((prop) => `${String(prop)}=${styles[prop]}`)
|
|
1054
|
+
.join(';');
|
|
1055
|
+
element.setAttribute('data-stash', stash);
|
|
1056
|
+
}
|
|
1057
|
+
function unstashStyles(element) {
|
|
1058
|
+
const stash = element.getAttribute('data-stash');
|
|
1059
|
+
if (stash === null) {
|
|
1060
|
+
return;
|
|
1061
|
+
}
|
|
1062
|
+
const attributes = stash
|
|
1063
|
+
.split(';')
|
|
1064
|
+
.map((attr) => attr.split('='));
|
|
1065
|
+
for (const [attr, value] of attributes) {
|
|
1066
|
+
element.style[attr] = value;
|
|
1067
|
+
}
|
|
1068
|
+
element.removeAttribute('data-stash');
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
var version = "2.0.0-rc.3";
|
|
1072
|
+
|
|
1073
|
+
/**
|
|
1074
|
+
* @license
|
|
1075
|
+
* @monterosa/sdk-launcher-kit
|
|
1076
|
+
*
|
|
1077
|
+
* Copyright © 2022-2026 Monterosa Productions Limited. All rights reserved.
|
|
1078
|
+
*
|
|
1079
|
+
* More details on the license can be found at https://www.monterosa.co/sdk/license
|
|
1080
|
+
*/
|
|
1081
|
+
/**
|
|
1082
|
+
* The current SDK version.
|
|
1083
|
+
*
|
|
1084
|
+
* @internal
|
|
1085
|
+
*/
|
|
1086
|
+
const VERSION = version;
|
|
1087
|
+
/**
|
|
1088
|
+
* Creates an iframe with the provided parameters.
|
|
1089
|
+
*
|
|
1090
|
+
* @param url Url of the web app.
|
|
1091
|
+
*
|
|
1092
|
+
* @private
|
|
1093
|
+
*/
|
|
1094
|
+
function createIFrame(url, options = {}) {
|
|
1095
|
+
const iframe = document.createElement('iframe');
|
|
1096
|
+
iframe.style.width = '100%';
|
|
1097
|
+
iframe.style.height = '100%';
|
|
1098
|
+
iframe.style.border = '0';
|
|
1099
|
+
iframe.style.display = 'block';
|
|
1100
|
+
iframe.style.boxSizing = 'border-box';
|
|
1101
|
+
iframe.setAttribute('src', url);
|
|
1102
|
+
if (options.id !== undefined) {
|
|
1103
|
+
iframe.setAttribute('id', options.id);
|
|
1104
|
+
}
|
|
1105
|
+
if (options.allow !== undefined) {
|
|
1106
|
+
iframe.setAttribute('allow', options.allow);
|
|
1107
|
+
}
|
|
1108
|
+
if (options.allowFullScreen === true) {
|
|
1109
|
+
iframe.setAttribute('allowfullscreen', '');
|
|
1110
|
+
}
|
|
1111
|
+
if (options.title !== undefined) {
|
|
1112
|
+
iframe.setAttribute('title', options.title);
|
|
1113
|
+
}
|
|
1114
|
+
/**
|
|
1115
|
+
* Though scrolling attribute is deprecated we still have to rely on it as some
|
|
1116
|
+
* browsers (e.g. Chrome, as of now version 103) just ignores overflow: hidden.
|
|
1117
|
+
* Hence we are setting scrolling to no in order to eliminate scroll and calculate
|
|
1118
|
+
* width of the child Experience correctly. If scroll persists it appears on each
|
|
1119
|
+
* content change what leads to incorrect width calculation.
|
|
1120
|
+
*
|
|
1121
|
+
* Later we will look into alternatives such as iframeless Experience embed
|
|
1122
|
+
*/
|
|
1123
|
+
if (!options.scrolling) {
|
|
1124
|
+
iframe.style.overflow = 'hidden';
|
|
1125
|
+
iframe.setAttribute('scrolling', 'no');
|
|
1126
|
+
}
|
|
1127
|
+
return iframe;
|
|
1128
|
+
}
|
|
1129
|
+
function concealIFrame(iframe) {
|
|
1130
|
+
iframe.style.opacity = '0';
|
|
1131
|
+
}
|
|
1132
|
+
function revealIFrame(iframe) {
|
|
1133
|
+
iframe.style.opacity = '1';
|
|
1134
|
+
}
|
|
1135
|
+
function isSdk(value) {
|
|
1136
|
+
return value instanceof sdkCore.Sdk;
|
|
1137
|
+
}
|
|
1138
|
+
function getExperience(sdkOrConfig, config) {
|
|
1139
|
+
let sdk;
|
|
1140
|
+
let experienceConfig;
|
|
1141
|
+
if (isSdk(sdkOrConfig)) {
|
|
1142
|
+
/**
|
|
1143
|
+
* Interface: getExperience(sdk, config?)
|
|
1144
|
+
*/
|
|
1145
|
+
sdk = sdkOrConfig;
|
|
1146
|
+
if (config !== undefined) {
|
|
1147
|
+
experienceConfig = config;
|
|
1148
|
+
}
|
|
1149
|
+
else {
|
|
1150
|
+
experienceConfig = {};
|
|
1151
|
+
}
|
|
1152
|
+
}
|
|
1153
|
+
else if (sdkOrConfig !== undefined) {
|
|
1154
|
+
/**
|
|
1155
|
+
* Interface: getExperience(config)
|
|
1156
|
+
*/
|
|
1157
|
+
sdk = sdkCore.getSdk();
|
|
1158
|
+
experienceConfig = sdkOrConfig;
|
|
1159
|
+
}
|
|
1160
|
+
else {
|
|
1161
|
+
/**
|
|
1162
|
+
* Interface: getExperience()
|
|
1163
|
+
*/
|
|
1164
|
+
sdk = sdkCore.getSdk();
|
|
1165
|
+
experienceConfig = {};
|
|
1166
|
+
}
|
|
1167
|
+
const experience = new ExperienceImpl(sdk, experienceConfig);
|
|
1168
|
+
return experience;
|
|
1169
|
+
}
|
|
1170
|
+
async function waitForAction(experience, action) {
|
|
1171
|
+
return new Promise((resolve) => {
|
|
1172
|
+
const unsubscribe = onSdkMessage(experience, (message) => {
|
|
1173
|
+
if (message.action === action) {
|
|
1174
|
+
unsubscribe();
|
|
1175
|
+
resolve();
|
|
1176
|
+
}
|
|
1177
|
+
});
|
|
1178
|
+
});
|
|
1179
|
+
}
|
|
1180
|
+
async function experienceReady(experience) {
|
|
1181
|
+
/**
|
|
1182
|
+
* Bumper delay during which loading state can't be hidden even
|
|
1183
|
+
* if Experience loaded earlier than timer reached bumper timeout
|
|
1184
|
+
*/
|
|
1185
|
+
const bumper = sdkUtil.delay(LOADER_BUMPER_TIMEOUT);
|
|
1186
|
+
/**
|
|
1187
|
+
* Final cut off timeout delay after which loading state must
|
|
1188
|
+
* be hidden even if Experience is still loading
|
|
1189
|
+
*/
|
|
1190
|
+
const timeout = sdkUtil.delay(LOADER_TIMEOUT);
|
|
1191
|
+
const loaded = waitForAction(experience, exports.Action.OnReady);
|
|
1192
|
+
const hasFullyLoadedExperience = Promise.all([bumper, loaded]);
|
|
1193
|
+
const eitherTimeoutOrFullyLoaded = Promise.race([
|
|
1194
|
+
timeout,
|
|
1195
|
+
hasFullyLoadedExperience,
|
|
1196
|
+
]);
|
|
1197
|
+
return eitherTimeoutOrFullyLoaded;
|
|
1198
|
+
}
|
|
1199
|
+
/**
|
|
1200
|
+
* Embeds a web Experience app into an iframe.
|
|
1201
|
+
*
|
|
1202
|
+
* @remarks
|
|
1203
|
+
* There is only one app that can be associated with an Experience and it is
|
|
1204
|
+
* configured in Monterosa / Interaction Cloud. Please refer to the developer
|
|
1205
|
+
* guide for more information:
|
|
1206
|
+
* {@link https://products.monterosa.co/mic/developer-guides/whats-an-app}
|
|
1207
|
+
*
|
|
1208
|
+
* @example
|
|
1209
|
+
* ```javascript
|
|
1210
|
+
* const experience = getExperience();
|
|
1211
|
+
*
|
|
1212
|
+
* embed(experience, 'container-id');
|
|
1213
|
+
* ```
|
|
1214
|
+
* @param experience - An instance of Experience
|
|
1215
|
+
* @param containerOrId - HTML element instance or
|
|
1216
|
+
* element id where iframe is embedded into.
|
|
1217
|
+
*
|
|
1218
|
+
* @public
|
|
1219
|
+
*/
|
|
1220
|
+
async function embed(experience, containerOrId) {
|
|
1221
|
+
const container = containerOrId instanceof HTMLElement
|
|
1222
|
+
? containerOrId
|
|
1223
|
+
: document.getElementById(containerOrId);
|
|
1224
|
+
if (container === null) {
|
|
1225
|
+
throw new Error(`Container element "${containerOrId}" not found in DOM. ` +
|
|
1226
|
+
'Please ensure the element exists before calling embed().');
|
|
1227
|
+
}
|
|
1228
|
+
if (hasIntegration(container)) {
|
|
1229
|
+
throw new Error('Container already contains an embedded experience. Use unmount() first ' +
|
|
1230
|
+
'to remove the existing experience before embedding a new one.');
|
|
1231
|
+
}
|
|
1232
|
+
if (hasIntegration(experience)) {
|
|
1233
|
+
throw new Error('This experience is already embedded in another container. Use unmount() ' +
|
|
1234
|
+
'to remove it from that container before embedding it into this one.');
|
|
1235
|
+
}
|
|
1236
|
+
const controller = new AbortController();
|
|
1237
|
+
const integration = {
|
|
1238
|
+
container,
|
|
1239
|
+
experience,
|
|
1240
|
+
controller,
|
|
1241
|
+
};
|
|
1242
|
+
addIntegration(container, integration);
|
|
1243
|
+
if (experience.config.supportsLoadingState === true) {
|
|
1244
|
+
// Although showLoader is an asynchronous function, we execute
|
|
1245
|
+
// it synchronously to embed the iframe as quickly as possible.
|
|
1246
|
+
show(container, experience.config.loadingTemplate);
|
|
1247
|
+
}
|
|
1248
|
+
const url = await experience.getUrl();
|
|
1249
|
+
if (controller.signal.aborted) {
|
|
1250
|
+
return;
|
|
1251
|
+
}
|
|
1252
|
+
const iframe = createIFrame(url, {
|
|
1253
|
+
id: experience.bridge.iFrameId,
|
|
1254
|
+
scrolling: !experience.config.autoresizesHeight,
|
|
1255
|
+
allow: experience.config.allow,
|
|
1256
|
+
allowFullScreen: experience.config.allowFullScreen,
|
|
1257
|
+
title: experience.config.title,
|
|
1258
|
+
});
|
|
1259
|
+
container.appendChild(iframe);
|
|
1260
|
+
concealIFrame(iframe);
|
|
1261
|
+
updateExperienceState(experience, 'mounted');
|
|
1262
|
+
await waitForAction(experience, exports.Action.OnInitialised);
|
|
1263
|
+
if (controller.signal.aborted) {
|
|
1264
|
+
return;
|
|
1265
|
+
}
|
|
1266
|
+
updateExperienceState(experience, 'initialised');
|
|
1267
|
+
await experienceReady(experience);
|
|
1268
|
+
if (controller.signal.aborted) {
|
|
1269
|
+
return;
|
|
1270
|
+
}
|
|
1271
|
+
updateExperienceState(experience, 'ready');
|
|
1272
|
+
revealIFrame(iframe);
|
|
1273
|
+
if (experience.config.supportsLoadingState === true) {
|
|
1274
|
+
await hide(container);
|
|
1275
|
+
}
|
|
1276
|
+
}
|
|
1277
|
+
/**
|
|
1278
|
+
* Removes an Experience from its container and resets its state to `unmounted`.
|
|
1279
|
+
*
|
|
1280
|
+
* This is the preferred method for removing an embedded Experience.
|
|
1281
|
+
* Use {@link onStateChanged} to observe when the Experience transitions
|
|
1282
|
+
* to the `unmounted` state.
|
|
1283
|
+
*
|
|
1284
|
+
* @example
|
|
1285
|
+
* ```javascript
|
|
1286
|
+
* const experience = getExperience(sdk, { eventId: 'poll-123' });
|
|
1287
|
+
* embed(experience, container);
|
|
1288
|
+
*
|
|
1289
|
+
* // Later, to remove:
|
|
1290
|
+
* unembed(experience);
|
|
1291
|
+
* ```
|
|
1292
|
+
*
|
|
1293
|
+
* @param experience - The Experience instance to unembed
|
|
1294
|
+
*
|
|
1295
|
+
* @public
|
|
1296
|
+
*/
|
|
1297
|
+
function unembed(experience) {
|
|
1298
|
+
const integration = getIntegration(experience);
|
|
1299
|
+
if (!integration) {
|
|
1300
|
+
throw new Error('This Experience is not currently embedded. ' +
|
|
1301
|
+
'Please ensure the Experience is embedded before calling unembed().');
|
|
1302
|
+
}
|
|
1303
|
+
const { container } = integration;
|
|
1304
|
+
integration.controller.abort();
|
|
1305
|
+
while (container.lastElementChild) {
|
|
1306
|
+
container.removeChild(container.lastElementChild);
|
|
1307
|
+
}
|
|
1308
|
+
deleteIntegration(container);
|
|
1309
|
+
container.style.height = '';
|
|
1310
|
+
updateExperienceState(experience, 'unmounted');
|
|
1311
|
+
}
|
|
1312
|
+
/**
|
|
1313
|
+
* Unmounts web Experience app which was previously embedded in the container.
|
|
1314
|
+
*
|
|
1315
|
+
* @deprecated Use {@link unembed} instead, which takes an Experience instance
|
|
1316
|
+
* rather than a container.
|
|
1317
|
+
*
|
|
1318
|
+
* @example
|
|
1319
|
+
* ```javascript
|
|
1320
|
+
* unmount('container-id');
|
|
1321
|
+
* ```
|
|
1322
|
+
*
|
|
1323
|
+
* @param {HTMLElement | string} containerOrId - HTML element instance or
|
|
1324
|
+
* element id where iframe is embedded into.
|
|
1325
|
+
*
|
|
1326
|
+
* @public
|
|
1327
|
+
*/
|
|
1328
|
+
function unmount(containerOrId) {
|
|
1329
|
+
console.warn('[launcher-kit] unmount() is deprecated. Use unembed(experience) instead.');
|
|
1330
|
+
const container = containerOrId instanceof HTMLElement
|
|
1331
|
+
? containerOrId
|
|
1332
|
+
: document.getElementById(containerOrId);
|
|
1333
|
+
if (container === null) {
|
|
1334
|
+
throw new Error(`Container element "${containerOrId}" not found in DOM. ` +
|
|
1335
|
+
'Please ensure the element exists before calling unmount().');
|
|
1336
|
+
}
|
|
1337
|
+
const integration = getIntegration(container);
|
|
1338
|
+
if (!integration) {
|
|
1339
|
+
throw new Error(`No Experience found embedded in container "${containerOrId}". ` +
|
|
1340
|
+
'Please ensure the Experience is embedded before calling unmount().');
|
|
1341
|
+
}
|
|
1342
|
+
integration.controller.abort();
|
|
1343
|
+
while (container.lastElementChild) {
|
|
1344
|
+
container.removeChild(container.lastElementChild);
|
|
1345
|
+
}
|
|
1346
|
+
deleteIntegration(container);
|
|
1347
|
+
container.style.height = '';
|
|
1348
|
+
updateExperienceState(integration.experience, 'unmounted');
|
|
1349
|
+
}
|
|
1350
|
+
/**
|
|
1351
|
+
* Informs the Experience that more data should be loaded and displayed on the UI.
|
|
1352
|
+
*
|
|
1353
|
+
* @remarks
|
|
1354
|
+
* One example is when Experience renders items feed partially. Once a user scrolled
|
|
1355
|
+
* to the bottom edge of the app, more elements to load is requested.
|
|
1356
|
+
*
|
|
1357
|
+
* @param experience - Experience instance
|
|
1358
|
+
*/
|
|
1359
|
+
function requestMoreData(experience) {
|
|
1360
|
+
sendSdkMessage(experience, exports.Action.OnMoreDataRequested);
|
|
1361
|
+
}
|
|
1362
|
+
function enableLogging(logLevelOrFlag = true) {
|
|
1363
|
+
if (typeof logLevelOrFlag === 'boolean') {
|
|
1364
|
+
logger.logLevel = logLevelOrFlag ? sdkCore.LogLevel.Verbose : sdkCore.LogLevel.Silent;
|
|
1365
|
+
return;
|
|
1366
|
+
}
|
|
1367
|
+
logger.logLevel = logLevelOrFlag;
|
|
1368
|
+
}
|
|
1369
|
+
|
|
1370
|
+
/**
|
|
1371
|
+
* @license
|
|
1372
|
+
* @monterosa/sdk-launcher-kit
|
|
1373
|
+
*
|
|
1374
|
+
* Copyright © 2022-2026 Monterosa Productions Limited. All rights reserved.
|
|
1375
|
+
*
|
|
1376
|
+
* More details on the license can be found at https://www.monterosa.co/sdk/license
|
|
1377
|
+
*/
|
|
1378
|
+
const ELEMENT_NAME = 'monterosa-experience';
|
|
1379
|
+
class MonterosaExperienceElement extends HTMLElement {
|
|
1380
|
+
constructor() {
|
|
1381
|
+
super(...arguments);
|
|
1382
|
+
this._experience = null;
|
|
1383
|
+
}
|
|
1384
|
+
/**
|
|
1385
|
+
* The host URL for the Experience.
|
|
1386
|
+
*/
|
|
1387
|
+
get host() {
|
|
1388
|
+
return this.getAttribute('host') || '';
|
|
1389
|
+
}
|
|
1390
|
+
/**
|
|
1391
|
+
* The project identifier.
|
|
1392
|
+
*/
|
|
1393
|
+
get projectId() {
|
|
1394
|
+
return this.getAttribute('projectId') || '';
|
|
1395
|
+
}
|
|
1396
|
+
/**
|
|
1397
|
+
* The event identifier (optional).
|
|
1398
|
+
*/
|
|
1399
|
+
get eventId() {
|
|
1400
|
+
return this.getAttribute('eventId') || undefined;
|
|
1401
|
+
}
|
|
1402
|
+
async connectedCallback() {
|
|
1403
|
+
const host = this.getAttribute('host');
|
|
1404
|
+
if (host === null) {
|
|
1405
|
+
throw new Error('Host attribute is not set for Experience element');
|
|
1406
|
+
}
|
|
1407
|
+
const projectId = this.getAttribute('projectId');
|
|
1408
|
+
if (projectId === null) {
|
|
1409
|
+
throw new Error('Project attribute is not set for Experience element');
|
|
1410
|
+
}
|
|
1411
|
+
const autoresizesHeight = this.getAttribute('autoresizesHeight') !== null;
|
|
1412
|
+
const hidesHeadersAndFooters = this.getAttribute('hidesHeadersAndFooters') !== null;
|
|
1413
|
+
const eventId = this.getAttribute('eventId') !== null
|
|
1414
|
+
? this.getAttribute('eventId')
|
|
1415
|
+
: undefined;
|
|
1416
|
+
const experienceUrl = this.getAttribute('experienceUrl') !== null
|
|
1417
|
+
? this.getAttribute('experienceUrl')
|
|
1418
|
+
: undefined;
|
|
1419
|
+
const allow = this.getAttribute('allow') !== null
|
|
1420
|
+
? this.getAttribute('allow')
|
|
1421
|
+
: undefined;
|
|
1422
|
+
const allowFullScreen = this.getAttribute('allowFullScreen') !== null;
|
|
1423
|
+
const parameters = {};
|
|
1424
|
+
for (let i = 0; i < this.attributes.length; i++) {
|
|
1425
|
+
const attr = this.attributes[i];
|
|
1426
|
+
if (attr.name.startsWith('param-')) {
|
|
1427
|
+
const paramName = attr.name.split('param-')[1];
|
|
1428
|
+
parameters[paramName] = attr.value;
|
|
1429
|
+
}
|
|
1430
|
+
}
|
|
1431
|
+
const title = this.getAttribute('title') !== null
|
|
1432
|
+
? this.getAttribute('title')
|
|
1433
|
+
: undefined;
|
|
1434
|
+
const sdk = sdkCore.configure({
|
|
1435
|
+
host,
|
|
1436
|
+
projectId,
|
|
1437
|
+
}, `${host}-${projectId}`);
|
|
1438
|
+
const experience = getExperience(sdk, {
|
|
1439
|
+
autoresizesHeight,
|
|
1440
|
+
eventId,
|
|
1441
|
+
hidesHeadersAndFooters,
|
|
1442
|
+
experienceUrl,
|
|
1443
|
+
allow,
|
|
1444
|
+
allowFullScreen,
|
|
1445
|
+
parameters,
|
|
1446
|
+
title,
|
|
1447
|
+
});
|
|
1448
|
+
// Link the custom element to the experience
|
|
1449
|
+
experience.customElement = this;
|
|
1450
|
+
this._experience = experience;
|
|
1451
|
+
embed(experience, this);
|
|
1452
|
+
// eslint-disable-next-line
|
|
1453
|
+
onSdkMessage(experience, ({ payload, action }) => {
|
|
1454
|
+
switch (action) {
|
|
1455
|
+
case exports.Action.OnInitialised:
|
|
1456
|
+
break;
|
|
1457
|
+
case exports.Action.OnResize: {
|
|
1458
|
+
// const { width, height } = payload;
|
|
1459
|
+
break;
|
|
1460
|
+
}
|
|
1461
|
+
case exports.Action.OnReady:
|
|
1462
|
+
this.dispatchEvent(new CustomEvent('ready', {
|
|
1463
|
+
bubbles: true,
|
|
1464
|
+
cancelable: false,
|
|
1465
|
+
composed: true,
|
|
1466
|
+
}));
|
|
1467
|
+
break;
|
|
1468
|
+
}
|
|
1469
|
+
});
|
|
1470
|
+
}
|
|
1471
|
+
disconnectedCallback() {
|
|
1472
|
+
const experience = this._experience;
|
|
1473
|
+
this._experience = null;
|
|
1474
|
+
if (experience) {
|
|
1475
|
+
try {
|
|
1476
|
+
unembed(experience);
|
|
1477
|
+
}
|
|
1478
|
+
catch (_a) {
|
|
1479
|
+
// Experience may already have been unembedded
|
|
1480
|
+
}
|
|
1481
|
+
}
|
|
1482
|
+
}
|
|
1483
|
+
}
|
|
1484
|
+
if (!customElements.get(ELEMENT_NAME)) {
|
|
1485
|
+
customElements.define(ELEMENT_NAME, MonterosaExperienceElement);
|
|
1486
|
+
}
|
|
1487
|
+
|
|
1488
|
+
/**
|
|
1489
|
+
* @license
|
|
1490
|
+
* @monterosa/sdk-launcher-kit
|
|
1491
|
+
*
|
|
1492
|
+
* Copyright © 2025-2026 Monterosa Productions Limited. All rights reserved.
|
|
1493
|
+
*
|
|
1494
|
+
* More details on the license can be found at https://www.monterosa.co/sdk/license
|
|
1495
|
+
*/
|
|
1496
|
+
const unsubs$1 = new Map();
|
|
1497
|
+
function handleExperienceEmbedded$1(experience) {
|
|
1498
|
+
if (!experience.config.autoresizesHeight) {
|
|
1499
|
+
return;
|
|
1500
|
+
}
|
|
1501
|
+
const integration = getIntegration(experience);
|
|
1502
|
+
if (!integration) {
|
|
1503
|
+
return;
|
|
1504
|
+
}
|
|
1505
|
+
const { container } = integration;
|
|
1506
|
+
const unsub = onSdkMessage(experience, ({ action, payload }) => {
|
|
1507
|
+
if (action === exports.Action.OnResize) {
|
|
1508
|
+
/**
|
|
1509
|
+
* Container width is maintained the same as it is defined in the parent
|
|
1510
|
+
* page to preserve its behaviour. Only the height is updated
|
|
1511
|
+
*/
|
|
1512
|
+
// container.style.width = `${payload.width}px`;
|
|
1513
|
+
container.style.height = `${payload.height}px`;
|
|
1514
|
+
}
|
|
1515
|
+
});
|
|
1516
|
+
unsubs$1.set(experience.id, unsub);
|
|
1517
|
+
}
|
|
1518
|
+
function handleExperienceUnmounted$1(experience) {
|
|
1519
|
+
const unsub = unsubs$1.get(experience.id);
|
|
1520
|
+
if (unsub) {
|
|
1521
|
+
unsub();
|
|
1522
|
+
unsubs$1.delete(experience.id);
|
|
1523
|
+
}
|
|
1524
|
+
}
|
|
1525
|
+
onStateChanged((experience, state) => {
|
|
1526
|
+
if (state === 'mounted') {
|
|
1527
|
+
handleExperienceEmbedded$1(experience);
|
|
1528
|
+
}
|
|
1529
|
+
else if (state === 'unmounted') {
|
|
1530
|
+
handleExperienceUnmounted$1(experience);
|
|
1531
|
+
}
|
|
1532
|
+
});
|
|
1533
|
+
|
|
1534
|
+
/**
|
|
1535
|
+
* @license
|
|
1536
|
+
* @monterosa/sdk-launcher-kit
|
|
1537
|
+
*
|
|
1538
|
+
* Copyright © 2022 Monterosa Productions Limited. All rights reserved.
|
|
1539
|
+
*
|
|
1540
|
+
* More details on the license can be found at https://www.monterosa.co/sdk/license
|
|
1541
|
+
*/
|
|
1542
|
+
/**
|
|
1543
|
+
* @internal
|
|
1544
|
+
*/
|
|
1545
|
+
class ParentApplicationImpl {
|
|
1546
|
+
constructor(bridge) {
|
|
1547
|
+
this.bridge = bridge;
|
|
1548
|
+
}
|
|
1549
|
+
}
|
|
1550
|
+
|
|
1551
|
+
/**
|
|
1552
|
+
* @license
|
|
1553
|
+
* @monterosa/sdk-launcher-kit
|
|
1554
|
+
*
|
|
1555
|
+
* Copyright © 2023 Monterosa Productions Limited. All rights reserved.
|
|
1556
|
+
*
|
|
1557
|
+
* More details on the license can be found at https://www.monterosa.co/sdk/license
|
|
1558
|
+
*/
|
|
1559
|
+
let parentApplication;
|
|
1560
|
+
/**
|
|
1561
|
+
* Returns instance of parent application.
|
|
1562
|
+
*
|
|
1563
|
+
* @returns Returns {@link ParentApplication}
|
|
1564
|
+
* if an Experience resides within the parent application, and it was embedded
|
|
1565
|
+
* using {@link embed} function. Otherwise it returns `null`.
|
|
1566
|
+
*/
|
|
1567
|
+
function getParentApplication() {
|
|
1568
|
+
if (parentApplication !== undefined) {
|
|
1569
|
+
return parentApplication;
|
|
1570
|
+
}
|
|
1571
|
+
const parentBridge = getParentBridge();
|
|
1572
|
+
if (parentBridge === null) {
|
|
1573
|
+
return null;
|
|
1574
|
+
}
|
|
1575
|
+
parentApplication = new ParentApplicationImpl(parentBridge);
|
|
1576
|
+
return parentApplication;
|
|
1577
|
+
}
|
|
1578
|
+
|
|
1579
|
+
/**
|
|
1580
|
+
* @license
|
|
1581
|
+
* @monterosa/sdk-launcher-kit
|
|
1582
|
+
*
|
|
1583
|
+
* Copyright © 2022-2026 Monterosa Productions Limited. All rights reserved.
|
|
1584
|
+
*
|
|
1585
|
+
* More details on the license can be found at https://www.monterosa.co/sdk/license
|
|
1586
|
+
*/
|
|
1587
|
+
function getUrlParam(param) {
|
|
1588
|
+
let queryString = {};
|
|
1589
|
+
if (typeof window !== 'undefined') {
|
|
1590
|
+
queryString = window.location.search;
|
|
1591
|
+
}
|
|
1592
|
+
const urlParams = new URLSearchParams(queryString);
|
|
1593
|
+
return urlParams.get(param);
|
|
1594
|
+
}
|
|
1595
|
+
/**
|
|
1596
|
+
* Returns whether the Experience should hide its header and footer.
|
|
1597
|
+
*
|
|
1598
|
+
* @remarks
|
|
1599
|
+
* The SDK on the parent application will by default request a child
|
|
1600
|
+
* Experience to hide its header and footer by setting a query parameter called
|
|
1601
|
+
* `micHideHeaderAndFooter` to `1`.
|
|
1602
|
+
*
|
|
1603
|
+
* When true, the developer of a child Experience is expected to hide it's headers
|
|
1604
|
+
* and footers as the parent application is actively providing them.
|
|
1605
|
+
*
|
|
1606
|
+
* You can test whether you are respecting this correctly by adding the following query
|
|
1607
|
+
* to your URL:
|
|
1608
|
+
*
|
|
1609
|
+
* "?micHideHeaderAndFooter=1"
|
|
1610
|
+
*
|
|
1611
|
+
* @returns Whether the header and footer views should be hidden.
|
|
1612
|
+
*/
|
|
1613
|
+
function shouldHideHeaderAndFooter() {
|
|
1614
|
+
return getUrlParam(exports.QueryParam.HideHeaderAndFooter) === '1';
|
|
1615
|
+
}
|
|
1616
|
+
/**
|
|
1617
|
+
* This function will returns true if experience is embedded in autoresize height mode.
|
|
1618
|
+
*/
|
|
1619
|
+
function isAutoresizesHeight() {
|
|
1620
|
+
return getUrlParam(exports.QueryParam.AutoresizesHeight) === '1';
|
|
1621
|
+
}
|
|
1622
|
+
/**
|
|
1623
|
+
* Notifies the parent application that the Experience has initialised and
|
|
1624
|
+
* is ready to receive messages. This triggers the `initialised` lifecycle state.
|
|
1625
|
+
*
|
|
1626
|
+
* Call this method when your Experience has completed its initial setup and
|
|
1627
|
+
* is ready to receive configuration or other messages from the parent application.
|
|
1628
|
+
*
|
|
1629
|
+
* @example
|
|
1630
|
+
* ```javascript
|
|
1631
|
+
* import { sendInitialised } from '@monterosa/sdk-launcher-kit';
|
|
1632
|
+
*
|
|
1633
|
+
* // After your Experience has initialised
|
|
1634
|
+
* sendInitialised();
|
|
1635
|
+
* ```
|
|
1636
|
+
*/
|
|
1637
|
+
function sendInitialised() {
|
|
1638
|
+
const parentApp = getParentApplication();
|
|
1639
|
+
if (parentApp === null) {
|
|
1640
|
+
console.log('Unable to send initialised message, as there is no parent application');
|
|
1641
|
+
return;
|
|
1642
|
+
}
|
|
1643
|
+
sendSdkRequest(parentApp, exports.Action.OnInitialised);
|
|
1644
|
+
}
|
|
1645
|
+
/**
|
|
1646
|
+
* Notifies the parent application that the Experience UI is fully loaded
|
|
1647
|
+
* and ready to be displayed. This triggers the `ready` lifecycle state.
|
|
1648
|
+
*
|
|
1649
|
+
* @remarks
|
|
1650
|
+
* Call this method when your UI has completed loading and you are ready to
|
|
1651
|
+
* display data to the user. This can be when your network calls have successfully
|
|
1652
|
+
* requested data and you have updated the DOM, or when an error has occurred and
|
|
1653
|
+
* you want to take over the UI to provide details to the user.
|
|
1654
|
+
*
|
|
1655
|
+
* The SDK will use this message to dismiss the loading indicator, allowing a
|
|
1656
|
+
* seamless transition between a native loading UI and the fully loaded Experience.
|
|
1657
|
+
*
|
|
1658
|
+
* If this call is not made, the parent SDK will add a grace period to ensure
|
|
1659
|
+
* the web app has sufficient time to load, and eventually dismiss the loading
|
|
1660
|
+
* state to avoid infinite loading scenarios.
|
|
1661
|
+
*
|
|
1662
|
+
* @example
|
|
1663
|
+
* ```javascript
|
|
1664
|
+
* import { sendReady } from '@monterosa/sdk-launcher-kit';
|
|
1665
|
+
*
|
|
1666
|
+
* // After your UI has finished loading
|
|
1667
|
+
* sendReady();
|
|
1668
|
+
* ```
|
|
1669
|
+
*/
|
|
1670
|
+
function sendReady() {
|
|
1671
|
+
const parentApp = getParentApplication();
|
|
1672
|
+
if (parentApp === null) {
|
|
1673
|
+
console.log('Unable to send ready message, as there is no parent application');
|
|
1674
|
+
return;
|
|
1675
|
+
}
|
|
1676
|
+
sendSdkMessage(parentApp, exports.Action.OnReady);
|
|
1677
|
+
}
|
|
1678
|
+
/**
|
|
1679
|
+
* @deprecated Use {@link sendReady} instead.
|
|
1680
|
+
*
|
|
1681
|
+
* Sends a message to the SDK of the parent application informing it that
|
|
1682
|
+
* the UI of this Experience has completed loading.
|
|
1683
|
+
*/
|
|
1684
|
+
function sendFinishedLoadingUI() {
|
|
1685
|
+
console.warn('[launcher-kit] sendFinishedLoadingUI() is deprecated. Use sendReady() instead.');
|
|
1686
|
+
sendReady();
|
|
1687
|
+
}
|
|
1688
|
+
/**
|
|
1689
|
+
* Adds an observer for when more data is requested by the parent application
|
|
1690
|
+
*
|
|
1691
|
+
* @param callback - The callback that is triggered when a request for more data
|
|
1692
|
+
* is received
|
|
1693
|
+
* @returns The unsubscribe function. When it's called,
|
|
1694
|
+
* the observer will be removed and requests for data will no longer be received
|
|
1695
|
+
*/
|
|
1696
|
+
function onMoreDataRequested(callback) {
|
|
1697
|
+
const parentApp = getParentApplication();
|
|
1698
|
+
if (parentApp === null) {
|
|
1699
|
+
console.log('Unable to subscribe to more data event, as there is no parent application');
|
|
1700
|
+
return () => { };
|
|
1701
|
+
}
|
|
1702
|
+
return onSdkMessage(parentApp, ({ action }) => {
|
|
1703
|
+
if (action === exports.Action.OnMoreDataRequested) {
|
|
1704
|
+
callback();
|
|
1705
|
+
}
|
|
1706
|
+
});
|
|
1707
|
+
}
|
|
1708
|
+
/**
|
|
1709
|
+
* Adds an observer for when experience is fully embedded and ready to accept
|
|
1710
|
+
* incoming messages
|
|
1711
|
+
*
|
|
1712
|
+
* @deprecated Use `onStateChanged(experience, (state) => {
|
|
1713
|
+
* if (state === 'initialised') ...
|
|
1714
|
+
* })` instead.
|
|
1715
|
+
*
|
|
1716
|
+
* @param experience - Experience instance
|
|
1717
|
+
* @param callback - The callback that is triggered when experience is embedded
|
|
1718
|
+
* @returns The unsubscribe function. When it's called, the observer will be
|
|
1719
|
+
* removed and ready event will not be received
|
|
1720
|
+
*/
|
|
1721
|
+
function onReady(experience, callback) {
|
|
1722
|
+
console.warn('[launcher-kit] onReady() is deprecated. Use onStateChanged(' +
|
|
1723
|
+
"experience, (state) => { if (state === 'initialised') ... }) instead.");
|
|
1724
|
+
return onSdkMessage(experience, ({ action }) => {
|
|
1725
|
+
if (action === exports.Action.OnInitialised) {
|
|
1726
|
+
callback();
|
|
1727
|
+
}
|
|
1728
|
+
});
|
|
1729
|
+
}
|
|
1730
|
+
/**
|
|
1731
|
+
* @internal
|
|
1732
|
+
*/
|
|
1733
|
+
const sendExperienceSizeThrottled = sdkUtil.throttle((width, height) => {
|
|
1734
|
+
const parentApp = getParentApplication();
|
|
1735
|
+
if (parentApp !== null) {
|
|
1736
|
+
sendSdkMessage(parentApp, exports.Action.OnResize, { width, height });
|
|
1737
|
+
}
|
|
1738
|
+
}, RESIZE_THROTTLE_TIMEOUT, {
|
|
1739
|
+
leading: true,
|
|
1740
|
+
trailing: true,
|
|
1741
|
+
});
|
|
1742
|
+
/**
|
|
1743
|
+
* Sends the Experience size to the parent page.
|
|
1744
|
+
*
|
|
1745
|
+
* @param width - The width of the Experience.
|
|
1746
|
+
* @param height - The height of the Experience.
|
|
1747
|
+
*/
|
|
1748
|
+
function sendExperienceSize(width, height) {
|
|
1749
|
+
sendExperienceSizeThrottled(width, height);
|
|
1750
|
+
}
|
|
1751
|
+
/**
|
|
1752
|
+
* Sets up an observer to watch for the element dimensions change and
|
|
1753
|
+
* automatically reports their changes to the parent application.
|
|
1754
|
+
*
|
|
1755
|
+
* @param element - HTML element whose dimensions need to be watched
|
|
1756
|
+
* @returns The unsubscribe function. When it's called,
|
|
1757
|
+
* the observer will be removed and element dimensions are no longer tracked
|
|
1758
|
+
*/
|
|
1759
|
+
function reportExperienceSizeChanges(element) {
|
|
1760
|
+
const observer = new ResizeObserver(() => {
|
|
1761
|
+
const width = Math.max(element.offsetWidth, element.scrollWidth);
|
|
1762
|
+
const height = Math.max(element.offsetHeight, element.scrollHeight);
|
|
1763
|
+
sendExperienceSize(width, height);
|
|
1764
|
+
});
|
|
1765
|
+
observer.observe(element);
|
|
1766
|
+
return () => observer.unobserve(element);
|
|
1767
|
+
}
|
|
1768
|
+
|
|
1769
|
+
/**
|
|
1770
|
+
* @license
|
|
1771
|
+
* share.ts
|
|
1772
|
+
* launcher-kit
|
|
1773
|
+
*
|
|
1774
|
+
* Copyright © 2026 Monterosa Productions Limited. All rights reserved.
|
|
1775
|
+
*
|
|
1776
|
+
* More details on the license can be found at https://www.monterosa.co/sdk/license
|
|
1777
|
+
*/
|
|
1778
|
+
/**
|
|
1779
|
+
* Share requests block on the native share tray which waits for user
|
|
1780
|
+
* interaction (composing a message, picking a target app, etc.). The default
|
|
1781
|
+
* bridge timeout of 20 seconds is too short for this. 5 minutes gives users
|
|
1782
|
+
* ample time while still acting as a safety net against lost messages.
|
|
1783
|
+
*/
|
|
1784
|
+
const SHARE_REQUEST_TIMEOUT = 300000;
|
|
1785
|
+
exports.ShareError = void 0;
|
|
1786
|
+
(function (ShareError) {
|
|
1787
|
+
ShareError["ParentAppError"] = "parent_app_error";
|
|
1788
|
+
ShareError["ShareFailed"] = "share_failed";
|
|
1789
|
+
})(exports.ShareError || (exports.ShareError = {}));
|
|
1790
|
+
const ShareErrorMessages = {
|
|
1791
|
+
[exports.ShareError.ParentAppError]: (error) => `Parent application error: ${error}`,
|
|
1792
|
+
[exports.ShareError.ShareFailed]: (error) => `Share failed: ${error}`,
|
|
1793
|
+
};
|
|
1794
|
+
/**
|
|
1795
|
+
* Executes share using the Web Share API.
|
|
1796
|
+
*
|
|
1797
|
+
* @internal
|
|
1798
|
+
*/
|
|
1799
|
+
async function executeShare(data) {
|
|
1800
|
+
try {
|
|
1801
|
+
await navigator.share({
|
|
1802
|
+
url: data.url,
|
|
1803
|
+
title: data.title,
|
|
1804
|
+
text: data.description,
|
|
1805
|
+
});
|
|
1806
|
+
return 'success';
|
|
1807
|
+
}
|
|
1808
|
+
catch (err) {
|
|
1809
|
+
if (err instanceof DOMException && err.name === 'AbortError') {
|
|
1810
|
+
return 'cancelled';
|
|
1811
|
+
}
|
|
1812
|
+
throw sdkUtil.createError(exports.ShareError.ShareFailed, ShareErrorMessages, sdkUtil.getErrorMessage(err));
|
|
1813
|
+
}
|
|
1814
|
+
}
|
|
1815
|
+
/**
|
|
1816
|
+
* Initiates a share action. When running inside a parent application,
|
|
1817
|
+
* the share request is sent to the parent via the communication bridge.
|
|
1818
|
+
* When running standalone, `navigator.share()` is called directly.
|
|
1819
|
+
*
|
|
1820
|
+
* @param data - The data to share
|
|
1821
|
+
*/
|
|
1822
|
+
async function share(data) {
|
|
1823
|
+
const parentApp = getParentApplication();
|
|
1824
|
+
if (parentApp !== null) {
|
|
1825
|
+
const response = await sendSdkRequest(parentApp, exports.Action.OnShare, data, SHARE_REQUEST_TIMEOUT);
|
|
1826
|
+
if (response.payload.result === 'failure') {
|
|
1827
|
+
throw sdkUtil.createError(exports.ShareError.ParentAppError, ShareErrorMessages, response.payload.message);
|
|
1828
|
+
}
|
|
1829
|
+
// 'success' and 'cancelled' both resolve silently
|
|
1830
|
+
return;
|
|
1831
|
+
}
|
|
1832
|
+
await executeShare(data);
|
|
1833
|
+
}
|
|
1834
|
+
/**
|
|
1835
|
+
* Registers a callback to be called when a share request is received
|
|
1836
|
+
* from a child Experience.
|
|
1837
|
+
*
|
|
1838
|
+
* @param experience - The Experience instance to listen on
|
|
1839
|
+
* @param callback - Called with ShareData when a share request is received
|
|
1840
|
+
* @returns Unsubscribe function
|
|
1841
|
+
*/
|
|
1842
|
+
function onShare(experience, callback) {
|
|
1843
|
+
return onSdkMessage(experience, (message) => {
|
|
1844
|
+
if (message.action === exports.Action.OnShare) {
|
|
1845
|
+
callback(message.payload);
|
|
1846
|
+
}
|
|
1847
|
+
});
|
|
1848
|
+
}
|
|
1849
|
+
const unsubs = new Map();
|
|
1850
|
+
function handleExperienceEmbedded(experience) {
|
|
1851
|
+
const unsub = onSdkMessage(experience, async (message) => {
|
|
1852
|
+
if (message.action !== exports.Action.OnShare) {
|
|
1853
|
+
return;
|
|
1854
|
+
}
|
|
1855
|
+
try {
|
|
1856
|
+
const parentApp = getParentApplication();
|
|
1857
|
+
let payload;
|
|
1858
|
+
if (parentApp !== null) {
|
|
1859
|
+
const response = await sendSdkRequest(parentApp, exports.Action.OnShare, message.payload, SHARE_REQUEST_TIMEOUT);
|
|
1860
|
+
payload = response.payload;
|
|
1861
|
+
}
|
|
1862
|
+
else {
|
|
1863
|
+
const result = await executeShare(message.payload);
|
|
1864
|
+
payload = {
|
|
1865
|
+
result,
|
|
1866
|
+
message: result === 'success' ? 'Share successful' : 'Share cancelled',
|
|
1867
|
+
data: {},
|
|
1868
|
+
};
|
|
1869
|
+
}
|
|
1870
|
+
respondToSdkMessage(experience, message, payload);
|
|
1871
|
+
}
|
|
1872
|
+
catch (err) {
|
|
1873
|
+
respondToSdkMessage(experience, message, {
|
|
1874
|
+
result: 'failure',
|
|
1875
|
+
message: sdkUtil.getErrorMessage(err),
|
|
1876
|
+
data: {},
|
|
1877
|
+
});
|
|
1878
|
+
}
|
|
1879
|
+
});
|
|
1880
|
+
unsubs.set(experience.id, unsub);
|
|
1881
|
+
}
|
|
1882
|
+
function handleExperienceUnmounted(experience) {
|
|
1883
|
+
const unsub = unsubs.get(experience.id);
|
|
1884
|
+
if (unsub) {
|
|
1885
|
+
unsub();
|
|
1886
|
+
unsubs.delete(experience.id);
|
|
1887
|
+
}
|
|
1888
|
+
}
|
|
1889
|
+
onStateChanged((experience, state) => {
|
|
1890
|
+
if (state === 'mounted') {
|
|
1891
|
+
handleExperienceEmbedded(experience);
|
|
1892
|
+
}
|
|
1893
|
+
else if (state === 'unmounted') {
|
|
1894
|
+
handleExperienceUnmounted(experience);
|
|
1895
|
+
}
|
|
1896
|
+
});
|
|
1897
|
+
|
|
1898
|
+
exports.BRIDGE_VERSION = VERSION$1;
|
|
1899
|
+
exports.BridgeImpl = BridgeImpl;
|
|
1900
|
+
exports.ExperienceImpl = ExperienceImpl;
|
|
1901
|
+
exports.ParentApplicationImpl = ParentApplicationImpl;
|
|
1902
|
+
exports.ShareErrorMessages = ShareErrorMessages;
|
|
1903
|
+
exports.VERSION = VERSION;
|
|
1904
|
+
exports.embed = embed;
|
|
1905
|
+
exports.enableLogging = enableLogging;
|
|
1906
|
+
exports.executeShare = executeShare;
|
|
1907
|
+
exports.getBridge = getBridge;
|
|
1908
|
+
exports.getExperience = getExperience;
|
|
1909
|
+
exports.getParentApplication = getParentApplication;
|
|
1910
|
+
exports.getParentBridge = getParentBridge;
|
|
1911
|
+
exports.isAutoresizesHeight = isAutoresizesHeight;
|
|
1912
|
+
exports.isInsideIframe = isInsideIframe;
|
|
1913
|
+
exports.onMessage = onMessage;
|
|
1914
|
+
exports.onMoreDataRequested = onMoreDataRequested;
|
|
1915
|
+
exports.onReady = onReady;
|
|
1916
|
+
exports.onSdkMessage = onSdkMessage;
|
|
1917
|
+
exports.onShare = onShare;
|
|
1918
|
+
exports.onStateChanged = onStateChanged;
|
|
1919
|
+
exports.reportExperienceSizeChanges = reportExperienceSizeChanges;
|
|
1920
|
+
exports.requestMoreData = requestMoreData;
|
|
1921
|
+
exports.respondToMessage = respondToMessage;
|
|
1922
|
+
exports.respondToSdkMessage = respondToSdkMessage;
|
|
1923
|
+
exports.sendExperienceSize = sendExperienceSize;
|
|
1924
|
+
exports.sendExperienceSizeThrottled = sendExperienceSizeThrottled;
|
|
1925
|
+
exports.sendFinishedLoadingUI = sendFinishedLoadingUI;
|
|
1926
|
+
exports.sendInitialised = sendInitialised;
|
|
1927
|
+
exports.sendMessage = sendMessage;
|
|
1928
|
+
exports.sendReady = sendReady;
|
|
1929
|
+
exports.sendRequest = sendRequest;
|
|
1930
|
+
exports.sendSdkMessage = sendSdkMessage;
|
|
1931
|
+
exports.sendSdkRequest = sendSdkRequest;
|
|
1932
|
+
exports.setRequestTimeout = setRequestTimeout;
|
|
1933
|
+
exports.share = share;
|
|
1934
|
+
exports.shouldHideHeaderAndFooter = shouldHideHeaderAndFooter;
|
|
1935
|
+
exports.stateEmitter = stateEmitter;
|
|
1936
|
+
exports.unembed = unembed;
|
|
1937
|
+
exports.unmount = unmount;
|
|
1938
|
+
exports.updateExperienceState = updateExperienceState;
|
|
1939
|
+
//# sourceMappingURL=index.cjs.map
|