@monterosa/sdk-interact-kit 0.19.0-rc.5 → 2.0.0-rc.1

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.
@@ -12,8 +12,8 @@ import { ElementContext } from './context';
12
12
  import { InteractEvent } from '../event/public-types';
13
13
  import { Answer } from './answer';
14
14
  export declare const elements: Map<string, InteractElement>;
15
- export declare function buildElement(options: ElementOptions, context: ElementContext): InteractElement;
15
+ export declare function buildElement(options: ElementOptions, context: ElementContext): Promise<InteractElement>;
16
16
  export declare function configureEvent(event: InteractEvent): Promise<void>;
17
17
  export declare function sendAnswer(element: InteractElement, userAnswer: Answer): Promise<void>;
18
- export declare function storeAnswer(element: InteractElement, userAnswer: Answer): void;
19
- export declare function restoreAnswer(element: InteractElement): void;
18
+ export declare function storeAnswer(element: InteractElement, userAnswer: Answer): Promise<void>;
19
+ export declare function restoreAnswer(element: InteractElement): Promise<void>;
@@ -20,6 +20,9 @@ export declare class EventImpl extends Emitter implements InteractEvent {
20
20
  private _internalState;
21
21
  private _initState;
22
22
  private _history;
23
+ private boundHandleState;
24
+ private boundHandleInternalState;
25
+ private boundHandleEventsUpdated;
23
26
  private unsubscribeStateHandler;
24
27
  private unsubscribeInternalStateHandler;
25
28
  private unsubscribeListingsHandler;
@@ -28,7 +31,7 @@ export declare class EventImpl extends Emitter implements InteractEvent {
28
31
  private calculateInternalState;
29
32
  private handleState;
30
33
  private handleInternalState;
31
- private handleListings;
34
+ private handleEventsUpdated;
32
35
  /** @internal */
33
36
  destroy(): void;
34
37
  get context(): EventContext;
@@ -8,7 +8,7 @@
8
8
  */
9
9
  import { MonterosaSdk } from '@monterosa/sdk-core';
10
10
  import { Unsubscribe } from '@monterosa/sdk-util';
11
- import { InteractProject, Listings } from './public-types';
11
+ import { InteractProject } from './public-types';
12
12
  /**
13
13
  * @internal
14
14
  */
@@ -18,17 +18,16 @@ declare const getProjectMemoized: (...args: any[]) => Promise<InteractProject>;
18
18
  * with the {@link @monterosa/sdk-core#MonterosaSdk | configured sdk}
19
19
  */
20
20
  declare function getProject(sdk?: MonterosaSdk): Promise<InteractProject>;
21
- /**
22
- * @internal
23
- */
24
- export declare function fetchListings(host: string, projectId: string): Promise<Listings>;
25
21
  /**
26
22
  * Adds an observer for when {@link InteractProject.fields | project fields}
27
23
  * are updated
28
24
  */
29
25
  declare function onProjectFieldsUpdated(project: InteractProject, callback: () => void): Unsubscribe;
30
26
  /**
31
- * @internal
27
+ * Adds an observer that is called when the project listings are updated.
28
+ *
29
+ * @deprecated Use {@link onEventAdded()}, {@link onEventUpdated()} and
30
+ * {@link onEventRemoved()} instead
32
31
  */
33
32
  declare function onProjectListingsUpdated(project: InteractProject, callback: () => void): Unsubscribe;
34
33
  export { getProject, getProjectMemoized, onProjectFieldsUpdated, onProjectListingsUpdated, };
@@ -34,6 +34,11 @@ export declare class ProjectImpl extends Emitter implements InteractProject {
34
34
  * Calculates events that were created (present in new listings but not in old)
35
35
  */
36
36
  private _calculateCreatedEvents;
37
+ /**
38
+ * Calculates events that were updated (present in old listings and new,
39
+ * but with different digest)
40
+ */
41
+ private _calculateUpdatedEvents;
37
42
  /**
38
43
  * Calculates events that were deleted (present in old listings but not in new)
39
44
  */
package/dist/index.cjs.js CHANGED
@@ -5,6 +5,8 @@ Object.defineProperty(exports, '__esModule', { value: true });
5
5
  var sdkConnectKit = require('@monterosa/sdk-connect-kit');
6
6
  var sdkUtil = require('@monterosa/sdk-util');
7
7
  var sdkCore = require('@monterosa/sdk-core');
8
+ var sdkInteractInterop = require('@monterosa/sdk-interact-interop');
9
+ var sdkStorageKit = require('@monterosa/sdk-storage-kit');
8
10
 
9
11
  /******************************************************************************
10
12
  Copyright (c) Microsoft Corporation.
@@ -493,31 +495,6 @@ function onConnectionHealthState(connectionHealth, callback) {
493
495
  return sdkUtil.subscribe(connectionHealth, 'state', callback);
494
496
  }
495
497
 
496
- /**
497
- * @license
498
- * @monterosa/sdk-interact-kit
499
- *
500
- * Copyright © 2022 Monterosa Productions Limited. All rights reserved.
501
- *
502
- * More details on the license can be found at https://www.monterosa.co/sdk/license
503
- */
504
- function fetchSettings(host, id) {
505
- return __awaiter(this, void 0, void 0, function () {
506
- var response, data;
507
- return __generator(this, function (_a) {
508
- switch (_a.label) {
509
- case 0: return [4 /*yield*/, fetch("https://".concat(host, "/projects/").concat(id.substring(0, 2), "/").concat(id, "/settings.json"))];
510
- case 1:
511
- response = _a.sent();
512
- return [4 /*yield*/, response.json()];
513
- case 2:
514
- data = _a.sent();
515
- return [2 /*return*/, data];
516
- }
517
- });
518
- });
519
- }
520
-
521
498
  /**
522
499
  * @license
523
500
  * @monterosa/sdk-interact-kit
@@ -651,11 +628,12 @@ var ProjectImpl = /** @class */ (function (_super) {
651
628
  },
652
629
  set: function (newListings) {
653
630
  var createdEvents = this._calculateCreatedEvents(newListings);
631
+ var updatedEvents = this._calculateUpdatedEvents(newListings);
654
632
  var deletedEvents = this._calculateDeletedEvents(newListings);
655
633
  this._listings = __assign({}, newListings);
656
634
  this._updateLocales(newListings);
657
635
  this._updateEventsChecksum(newListings);
658
- this._emitListingsEvents(createdEvents, deletedEvents);
636
+ this._emitListingsEvents(createdEvents, updatedEvents, deletedEvents);
659
637
  },
660
638
  enumerable: false,
661
639
  configurable: true
@@ -673,6 +651,25 @@ var ProjectImpl = /** @class */ (function (_super) {
673
651
  return !_this._listings.events.some(function (event) { return id === event.id; });
674
652
  });
675
653
  };
654
+ /**
655
+ * Calculates events that were updated (present in old listings and new,
656
+ * but with different digest)
657
+ */
658
+ ProjectImpl.prototype._calculateUpdatedEvents = function (newListings) {
659
+ var _this = this;
660
+ if (!this._listings) {
661
+ return [];
662
+ }
663
+ return newListings.events.filter(function (event) {
664
+ // find event data in new listings
665
+ var existingEvent = _this._listings.events.find(function (_a) {
666
+ var id = _a.id;
667
+ return event.id === id;
668
+ });
669
+ // return true if event data is found and digest is different
670
+ return existingEvent && event.digest !== existingEvent.digest;
671
+ });
672
+ };
676
673
  /**
677
674
  * Calculates events that were deleted (present in old listings but not in new)
678
675
  */
@@ -707,16 +704,20 @@ var ProjectImpl = /** @class */ (function (_super) {
707
704
  /**
708
705
  * Emits events based on created and deleted events
709
706
  */
710
- ProjectImpl.prototype._emitListingsEvents = function (createdEvents, deletedEvents) {
707
+ ProjectImpl.prototype._emitListingsEvents = function (createdEvents, updatedEvents, deletedEvents) {
711
708
  var hasCreatedEvents = createdEvents.length > 0;
712
709
  var hasDeletedEvents = deletedEvents.length > 0;
713
- var hasChanges = hasCreatedEvents || hasDeletedEvents;
710
+ var hasUpdatedEvents = updatedEvents.length > 0;
711
+ var hasChanges = hasCreatedEvents || hasDeletedEvents || hasUpdatedEvents;
714
712
  if (hasCreatedEvents) {
715
713
  this.emit('listings_events_created', createdEvents);
716
714
  }
717
715
  if (hasDeletedEvents) {
718
716
  this.emit('listings_events_deleted', deletedEvents);
719
717
  }
718
+ if (hasUpdatedEvents) {
719
+ this.emit('listings_events_updated', updatedEvents);
720
+ }
720
721
  if (hasChanges) {
721
722
  this.emit('listings');
722
723
  }
@@ -844,7 +845,7 @@ function buildProject(options, context) {
844
845
  throw new Error("Unable to fetch project ".concat(id, " listings. Possibly wrong project id."));
845
846
  }
846
847
  _a = project;
847
- return [4 /*yield*/, fetchSettings(project.host, project.id)];
848
+ return [4 /*yield*/, sdkInteractInterop.fetchSettings(project.host, project.id)];
848
849
  case 4:
849
850
  _a.fields = _b.sent();
850
851
  return [2 /*return*/, project];
@@ -928,7 +929,7 @@ function handleListings(project, data) {
928
929
  _d.trys.push([1, 4, , 5]);
929
930
  if (!(oldDigest !== undefined && newDigest !== oldDigest)) return [3 /*break*/, 3];
930
931
  _b = project;
931
- return [4 /*yield*/, fetchSettings(project.host, project.id)];
932
+ return [4 /*yield*/, sdkInteractInterop.fetchSettings(project.host, project.id)];
932
933
  case 2:
933
934
  _b.fields = _d.sent();
934
935
  _d.label = 3;
@@ -978,25 +979,6 @@ function getProject(sdk) {
978
979
  if (sdk === void 0) { sdk = sdkCore.getSdk(); }
979
980
  return getProjectMemoized(sdk);
980
981
  }
981
- /**
982
- * @internal
983
- */
984
- function fetchListings(host, projectId) {
985
- return __awaiter(this, void 0, void 0, function () {
986
- var response, data;
987
- return __generator(this, function (_a) {
988
- switch (_a.label) {
989
- case 0: return [4 /*yield*/, fetch("https://".concat(host, "/projects/").concat(projectId.substring(0, 2), "/").concat(projectId, "/listings.json"))];
990
- case 1:
991
- response = _a.sent();
992
- return [4 /*yield*/, response.json()];
993
- case 2:
994
- data = (_a.sent());
995
- return [2 /*return*/, data];
996
- }
997
- });
998
- });
999
- }
1000
982
  /**
1001
983
  * Adds an observer for when {@link InteractProject.fields | project fields}
1002
984
  * are updated
@@ -1005,9 +987,13 @@ function onProjectFieldsUpdated(project, callback) {
1005
987
  return sdkUtil.subscribe(project, 'updated', callback);
1006
988
  }
1007
989
  /**
1008
- * @internal
990
+ * Adds an observer that is called when the project listings are updated.
991
+ *
992
+ * @deprecated Use {@link onEventAdded()}, {@link onEventUpdated()} and
993
+ * {@link onEventRemoved()} instead
1009
994
  */
1010
995
  function onProjectListingsUpdated(project, callback) {
996
+ console.warn('onProjectListingsUpdated() is deprecated. Please use onEventAdded(), onEventUpdated() and onEventRemoved() instead');
1011
997
  return sdkUtil.subscribe(project, 'listings', callback);
1012
998
  }
1013
999
 
@@ -1101,11 +1087,12 @@ var EventImpl = /** @class */ (function (_super) {
1101
1087
  _this._context = context;
1102
1088
  _this._state = _this.calculateState();
1103
1089
  _this._internalState = _this.calculateInternalState();
1104
- _this.unsubscribeStateHandler = sdkUtil.onTick(function () { return _this.handleState(); });
1105
- _this.unsubscribeInternalStateHandler = sdkUtil.onTick(function () {
1106
- _this.handleInternalState();
1107
- });
1108
- _this.unsubscribeListingsHandler = onProjectListingsUpdated(context.project, function () { return _this.handleListings(); });
1090
+ _this.boundHandleState = _this.handleState.bind(_this);
1091
+ _this.boundHandleInternalState = _this.handleInternalState.bind(_this);
1092
+ _this.boundHandleEventsUpdated = _this.handleEventsUpdated.bind(_this);
1093
+ _this.unsubscribeStateHandler = sdkUtil.onTick(_this.boundHandleState);
1094
+ _this.unsubscribeInternalStateHandler = sdkUtil.onTick(_this.boundHandleInternalState);
1095
+ _this.unsubscribeListingsHandler = sdkUtil.subscribe(_this.context.project, 'listings_events_updated', _this.boundHandleEventsUpdated);
1109
1096
  return _this;
1110
1097
  }
1111
1098
  EventImpl.prototype.calculateState = function () {
@@ -1149,15 +1136,17 @@ var EventImpl = /** @class */ (function (_super) {
1149
1136
  this.emit('internal_state', internalState);
1150
1137
  }
1151
1138
  };
1152
- EventImpl.prototype.handleListings = function () {
1139
+ EventImpl.prototype.handleEventsUpdated = function (events) {
1153
1140
  var _this = this;
1154
- var project = this.context.project;
1155
- var data = project.events.find(function (_a) {
1141
+ var data = events.find(function (_a) {
1156
1142
  var id = _a.id;
1157
1143
  return id === _this.id;
1158
1144
  });
1159
1145
  if (data && this._data.digest !== data.digest) {
1160
1146
  this._data = data;
1147
+ // Forcing state recalculation to ensure the event is in the correct state
1148
+ this.handleState();
1149
+ this.handleInternalState();
1161
1150
  this.emit('updated');
1162
1151
  }
1163
1152
  };
@@ -1993,6 +1982,7 @@ var ElementImpl = /** @class */ (function (_super) {
1993
1982
  };
1994
1983
  ElementImpl.prototype.update = function (data) {
1995
1984
  this._data = data;
1985
+ this.handleState();
1996
1986
  };
1997
1987
  ElementImpl.prototype.destroy = function () {
1998
1988
  this.unsubscribeStateHandler();
@@ -2240,15 +2230,24 @@ var ElementImpl = /** @class */ (function (_super) {
2240
2230
  * More details on the license can be found at https://www.monterosa.co/sdk/license
2241
2231
  */
2242
2232
  var elements = new Map();
2243
- var storageAvailable = sdkUtil.checkAvailability();
2244
2233
  function buildElement(options, context) {
2245
- if (elements.has(options.id)) {
2246
- return elements.get(options.id);
2247
- }
2248
- var element = new ElementImpl(options, context);
2249
- restoreAnswer(element);
2250
- elements.set(element.id, element);
2251
- return element;
2234
+ return __awaiter(this, void 0, void 0, function () {
2235
+ var element;
2236
+ return __generator(this, function (_a) {
2237
+ switch (_a.label) {
2238
+ case 0:
2239
+ if (elements.has(options.id)) {
2240
+ return [2 /*return*/, elements.get(options.id)];
2241
+ }
2242
+ element = new ElementImpl(options, context);
2243
+ return [4 /*yield*/, restoreAnswer(element)];
2244
+ case 1:
2245
+ _a.sent();
2246
+ elements.set(element.id, element);
2247
+ return [2 /*return*/, element];
2248
+ }
2249
+ });
2250
+ });
2252
2251
  }
2253
2252
  function getElementByPolld(pollId) {
2254
2253
  return Array.from(elements.values()).find(function (element) { return element.pollId === pollId; });
@@ -2347,19 +2346,28 @@ function handleCreateMessage(message) {
2347
2346
  if (event === null) {
2348
2347
  return [2 /*return*/];
2349
2348
  }
2350
- if (elements.has(options.id)) {
2351
- element = elements.get(options.id);
2352
- if (options.updated_at > element.updatedAt) {
2353
- element.update(options);
2354
- event.emit('update', element);
2355
- }
2356
- }
2357
- else {
2358
- context = __assign(__assign({}, event.context), { event: event });
2359
- element = buildElement(options, context);
2360
- event.emit('publish', element);
2349
+ if (!elements.has(options.id)) return [3 /*break*/, 2];
2350
+ element = elements.get(options.id);
2351
+ if (options.updated_at > element.updatedAt ||
2352
+ // This is a workaround to handle a Studio issue when two /create/ messages
2353
+ // are sent upon correct option reveal. The first /create/ message contains
2354
+ // the same duration but a different updated_at timestamp. The second /create/
2355
+ // message contains the same updated_at timestamp but a different duration.
2356
+ // Therefore, we need to check if the duration is different to ensure that
2357
+ // the element is updated correctly.
2358
+ options.duration !== element.duration) {
2359
+ element.update(options);
2360
+ event.emit('update', element);
2361
2361
  }
2362
- return [2 /*return*/];
2362
+ return [3 /*break*/, 4];
2363
+ case 2:
2364
+ context = __assign(__assign({}, event.context), { event: event });
2365
+ return [4 /*yield*/, buildElement(options, context)];
2366
+ case 3:
2367
+ element = _a.sent();
2368
+ event.emit('publish', element);
2369
+ _a.label = 4;
2370
+ case 4: return [2 /*return*/];
2363
2371
  }
2364
2372
  });
2365
2373
  });
@@ -2408,32 +2416,70 @@ function handleRevealMessage(message) {
2408
2416
  if (!element) {
2409
2417
  return;
2410
2418
  }
2411
- element.correctOption = correctOption;
2412
- element.context.event.emit('update', element);
2419
+ if (element.correctOption !== correctOption) {
2420
+ element.correctOption = correctOption;
2421
+ element.context.event.emit('update', element);
2422
+ }
2413
2423
  }
2414
2424
  function handleEventHistory(history) {
2425
+ var _a, e_1, _b, _c;
2415
2426
  return __awaiter(this, void 0, void 0, function () {
2416
- var event, context, _i, _a, snapshot;
2417
- return __generator(this, function (_b) {
2418
- switch (_b.label) {
2427
+ var event, context, _d, _e, _f, snapshot, e_1_1;
2428
+ return __generator(this, function (_g) {
2429
+ switch (_g.label) {
2419
2430
  case 0:
2420
2431
  if (history.timeline.length === 0) {
2421
2432
  return [2 /*return*/];
2422
2433
  }
2423
2434
  return [4 /*yield*/, getEvent(history.config.id)];
2424
2435
  case 1:
2425
- event = _b.sent();
2436
+ event = _g.sent();
2426
2437
  if (event === null) {
2427
2438
  return [2 /*return*/];
2428
2439
  }
2429
2440
  context = __assign(__assign({}, event.context), { event: event });
2430
- for (_i = 0, _a = history.timeline; _i < _a.length; _i++) {
2431
- snapshot = _a[_i];
2432
- if (!elements.has(snapshot.id)) {
2433
- buildElement(snapshot, context);
2434
- }
2435
- }
2436
- return [2 /*return*/];
2441
+ _g.label = 2;
2442
+ case 2:
2443
+ _g.trys.push([2, 11, 12, 17]);
2444
+ _d = true, _e = __asyncValues(history.timeline);
2445
+ _g.label = 3;
2446
+ case 3: return [4 /*yield*/, _e.next()];
2447
+ case 4:
2448
+ if (!(_f = _g.sent(), _a = _f.done, !_a)) return [3 /*break*/, 10];
2449
+ _c = _f.value;
2450
+ _d = false;
2451
+ _g.label = 5;
2452
+ case 5:
2453
+ _g.trys.push([5, , 8, 9]);
2454
+ snapshot = _c;
2455
+ if (!!elements.has(snapshot.id)) return [3 /*break*/, 7];
2456
+ return [4 /*yield*/, buildElement(snapshot, context)];
2457
+ case 6:
2458
+ _g.sent();
2459
+ _g.label = 7;
2460
+ case 7: return [3 /*break*/, 9];
2461
+ case 8:
2462
+ _d = true;
2463
+ return [7 /*endfinally*/];
2464
+ case 9: return [3 /*break*/, 3];
2465
+ case 10: return [3 /*break*/, 17];
2466
+ case 11:
2467
+ e_1_1 = _g.sent();
2468
+ e_1 = { error: e_1_1 };
2469
+ return [3 /*break*/, 17];
2470
+ case 12:
2471
+ _g.trys.push([12, , 15, 16]);
2472
+ if (!(!_d && !_a && (_b = _e.return))) return [3 /*break*/, 14];
2473
+ return [4 /*yield*/, _b.call(_e)];
2474
+ case 13:
2475
+ _g.sent();
2476
+ _g.label = 14;
2477
+ case 14: return [3 /*break*/, 16];
2478
+ case 15:
2479
+ if (e_1) throw e_1.error;
2480
+ return [7 /*endfinally*/];
2481
+ case 16: return [7 /*endfinally*/];
2482
+ case 17: return [2 /*return*/];
2437
2483
  }
2438
2484
  });
2439
2485
  });
@@ -2462,27 +2508,41 @@ function sendAnswer(element, userAnswer) {
2462
2508
  });
2463
2509
  }
2464
2510
  function storeAnswer(element, userAnswer) {
2465
- try {
2466
- element.userAnswer = userAnswer;
2467
- if (storageAvailable) {
2468
- // Can throw a "QuotaExceededError" DOMException exception
2469
- // if the quota has been exceeded.
2470
- sdkUtil.setItem("element_".concat(element.id, "_vote"), JSON.stringify(userAnswer));
2471
- }
2472
- }
2473
- catch (err) {
2474
- if (err instanceof Error) {
2475
- console.warn("Can't store user answer: ".concat(err.message));
2476
- }
2477
- }
2511
+ return __awaiter(this, void 0, void 0, function () {
2512
+ var err_1;
2513
+ return __generator(this, function (_a) {
2514
+ switch (_a.label) {
2515
+ case 0:
2516
+ _a.trys.push([0, 2, , 3]);
2517
+ element.userAnswer = userAnswer;
2518
+ return [4 /*yield*/, sdkStorageKit.storageWrite("element_".concat(element.id, "_vote"), JSON.stringify(userAnswer))];
2519
+ case 1:
2520
+ _a.sent();
2521
+ return [3 /*break*/, 3];
2522
+ case 2:
2523
+ err_1 = _a.sent();
2524
+ console.warn("Failed to store user answer: ".concat(sdkUtil.getErrorMessage(err_1)));
2525
+ return [3 /*break*/, 3];
2526
+ case 3: return [2 /*return*/];
2527
+ }
2528
+ });
2529
+ });
2478
2530
  }
2479
2531
  function restoreAnswer(element) {
2480
- if (storageAvailable) {
2481
- var userAnswer = sdkUtil.getItem("element_".concat(element.id, "_vote"));
2482
- if (userAnswer !== null) {
2483
- element.userAnswer = Answer.fromJSON(userAnswer);
2484
- }
2485
- }
2532
+ return __awaiter(this, void 0, void 0, function () {
2533
+ var userAnswer;
2534
+ return __generator(this, function (_a) {
2535
+ switch (_a.label) {
2536
+ case 0: return [4 /*yield*/, sdkStorageKit.storageRead("element_".concat(element.id, "_vote"))];
2537
+ case 1:
2538
+ userAnswer = _a.sent();
2539
+ if (userAnswer !== null) {
2540
+ element.userAnswer = Answer.fromJSON(userAnswer);
2541
+ }
2542
+ return [2 /*return*/];
2543
+ }
2544
+ });
2545
+ });
2486
2546
  }
2487
2547
 
2488
2548
  /**
@@ -2867,7 +2927,6 @@ exports.ElementImpl = ElementImpl;
2867
2927
  exports.EventImpl = EventImpl;
2868
2928
  exports.ProjectImpl = ProjectImpl;
2869
2929
  exports.answer = answer;
2870
- exports.fetchListings = fetchListings;
2871
2930
  exports.getConnect = getConnect;
2872
2931
  exports.getConnectionHealth = getConnectionHealth;
2873
2932
  exports.getElement = getElement;