@usecsv/react 0.2.16 → 0.2.19

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/build/index.js CHANGED
@@ -1,12 +1,12 @@
1
1
  /*!
2
- * @usecsv/react v0.2.16
2
+ * @usecsv/react v0.2.19
3
3
  * (c) layercode
4
4
  * Released under the MIT License.
5
5
  */
6
6
 
7
7
  'use strict';
8
8
 
9
- /*! *****************************************************************************
9
+ /******************************************************************************
10
10
  Copyright (c) Microsoft Corporation.
11
11
 
12
12
  Permission to use, copy, modify, and/or distribute this software for any
@@ -34,12 +34,12 @@ function __rest(s, e) {
34
34
  }
35
35
 
36
36
  /*!
37
- * @usecsv/js v0.12.0
37
+ * @usecsv/js v0.14.0
38
38
  * (c) layercode
39
39
  * Released under the MIT License.
40
40
  */
41
41
 
42
- /*! *****************************************************************************
42
+ /******************************************************************************
43
43
  Copyright (c) Microsoft Corporation.
44
44
 
45
45
  Permission to use, copy, modify, and/or distribute this software for any
@@ -247,14 +247,14 @@ const deserializeError = (obj) => {
247
247
  * Listens for "call" messages coming from the remote, executes the corresponding method, and
248
248
  * responds with the return value.
249
249
  */
250
- var connectCallReceiver = (info, methods, log) => {
250
+ var connectCallReceiver = (info, serializedMethods, log) => {
251
251
  const { localName, local, remote, originForSending, originForReceiving, } = info;
252
252
  let destroyed = false;
253
253
  const handleMessageEvent = (event) => {
254
254
  if (event.source !== remote || event.data.penpal !== MessageType.Call) {
255
255
  return;
256
256
  }
257
- if (event.origin !== originForReceiving) {
257
+ if (originForReceiving !== '*' && event.origin !== originForReceiving) {
258
258
  log(`${localName} received message from origin ${event.origin} which did not match expected origin ${originForReceiving}`);
259
259
  return;
260
260
  }
@@ -304,7 +304,7 @@ var connectCallReceiver = (info, methods, log) => {
304
304
  }
305
305
  };
306
306
  };
307
- new Promise((resolve) => resolve(methods[methodName].apply(methods, args))).then(createPromiseHandler(Resolution.Fulfilled), createPromiseHandler(Resolution.Rejected));
307
+ new Promise((resolve) => resolve(serializedMethods[methodName].apply(serializedMethods, args))).then(createPromiseHandler(Resolution.Fulfilled), createPromiseHandler(Resolution.Rejected));
308
308
  };
309
309
  local.addEventListener(NativeEventType.Message, handleMessageEvent);
310
310
  return () => {
@@ -319,18 +319,86 @@ let id = 0;
319
319
  */
320
320
  var generateId = () => ++id;
321
321
 
322
+ const KEY_PATH_DELIMITER = '.';
323
+ const keyPathToSegments = (keyPath) => keyPath ? keyPath.split(KEY_PATH_DELIMITER) : [];
324
+ const segmentsToKeyPath = (segments) => segments.join(KEY_PATH_DELIMITER);
325
+ const createKeyPath = (key, prefix) => {
326
+ const segments = keyPathToSegments(prefix || '');
327
+ segments.push(key);
328
+ return segmentsToKeyPath(segments);
329
+ };
330
+ /**
331
+ * Given a `keyPath`, set it to be `value` on `subject`, creating any intermediate
332
+ * objects along the way.
333
+ *
334
+ * @param {Object} subject The object on which to set value.
335
+ * @param {string} keyPath The key path at which to set value.
336
+ * @param {Object} value The value to store at the given key path.
337
+ * @returns {Object} Updated subject.
338
+ */
339
+ const setAtKeyPath = (subject, keyPath, value) => {
340
+ const segments = keyPathToSegments(keyPath);
341
+ segments.reduce((prevSubject, key, idx) => {
342
+ if (typeof prevSubject[key] === 'undefined') {
343
+ prevSubject[key] = {};
344
+ }
345
+ if (idx === segments.length - 1) {
346
+ prevSubject[key] = value;
347
+ }
348
+ return prevSubject[key];
349
+ }, subject);
350
+ return subject;
351
+ };
352
+ /**
353
+ * Given a dictionary of (nested) keys to function, flatten them to a map
354
+ * from key path to function.
355
+ *
356
+ * @param {Object} methods The (potentially nested) object to serialize.
357
+ * @param {string} prefix A string with which to prefix entries. Typically not intended to be used by consumers.
358
+ * @returns {Object} An map from key path in `methods` to functions.
359
+ */
360
+ const serializeMethods = (methods, prefix) => {
361
+ const flattenedMethods = {};
362
+ Object.keys(methods).forEach((key) => {
363
+ const value = methods[key];
364
+ const keyPath = createKeyPath(key, prefix);
365
+ if (typeof value === 'object') {
366
+ // Recurse into any nested children.
367
+ Object.assign(flattenedMethods, serializeMethods(value, keyPath));
368
+ }
369
+ if (typeof value === 'function') {
370
+ // If we've found a method, expose it.
371
+ flattenedMethods[keyPath] = value;
372
+ }
373
+ });
374
+ return flattenedMethods;
375
+ };
376
+ /**
377
+ * Given a map of key paths to functions, unpack the key paths to an object.
378
+ *
379
+ * @param {Object} flattenedMethods A map of key paths to functions to unpack.
380
+ * @returns {Object} A (potentially nested) map of functions.
381
+ */
382
+ const deserializeMethods = (flattenedMethods) => {
383
+ const methods = {};
384
+ for (const keyPath in flattenedMethods) {
385
+ setAtKeyPath(methods, keyPath, flattenedMethods[keyPath]);
386
+ }
387
+ return methods;
388
+ };
389
+
322
390
  /**
323
391
  * Augments an object with methods that match those defined by the remote. When these methods are
324
392
  * called, a "call" message will be sent to the remote, the remote's corresponding method will be
325
393
  * executed, and the method's return value will be returned via a message.
326
394
  * @param {Object} callSender Sender object that should be augmented with methods.
327
395
  * @param {Object} info Information about the local and remote windows.
328
- * @param {Array} methodNames Names of methods available to be called on the remote.
396
+ * @param {Array} methodKeyPaths Key paths of methods available to be called on the remote.
329
397
  * @param {Promise} destructionPromise A promise resolved when destroy() is called on the penpal
330
398
  * connection.
331
399
  * @returns {Object} The call sender object with methods that may be called.
332
400
  */
333
- var connectCallSender = (callSender, info, methodNames, destroyConnection, log) => {
401
+ var connectCallSender = (callSender, info, methodKeyPaths, destroyConnection, log) => {
334
402
  const { localName, local, remote, originForSending, originForReceiving, } = info;
335
403
  let destroyed = false;
336
404
  log(`${localName}: Connecting call sender`);
@@ -371,7 +439,8 @@ var connectCallSender = (callSender, info, methodNames, destroyConnection, log)
371
439
  event.data.id !== id) {
372
440
  return;
373
441
  }
374
- if (event.origin !== originForReceiving) {
442
+ if (originForReceiving !== '*' &&
443
+ event.origin !== originForReceiving) {
375
444
  log(`${localName} received message from origin ${event.origin} which did not match expected origin ${originForReceiving}`);
376
445
  return;
377
446
  }
@@ -395,10 +464,14 @@ var connectCallSender = (callSender, info, methodNames, destroyConnection, log)
395
464
  });
396
465
  };
397
466
  };
398
- methodNames.reduce((api, methodName) => {
399
- api[methodName] = createMethodProxy(methodName);
467
+ // Wrap each method in a proxy which sends it to the corresponding receiver.
468
+ const flattenedMethods = methodKeyPaths.reduce((api, name) => {
469
+ api[name] = createMethodProxy(name);
400
470
  return api;
401
- }, callSender);
471
+ }, {});
472
+ // Unpack the structure of the provided methods object onto the CallSender, exposing
473
+ // the methods in the same shape they were provided.
474
+ Object.assign(callSender, deserializeMethods(flattenedMethods));
402
475
  return () => {
403
476
  destroyed = true;
404
477
  };
@@ -407,7 +480,7 @@ var connectCallSender = (callSender, info, methodNames, destroyConnection, log)
407
480
  /**
408
481
  * Handles an ACK handshake message.
409
482
  */
410
- var handleAckMessageFactory = (methods, childOrigin, originForSending, destructor, log) => {
483
+ var handleAckMessageFactory = (serializedMethods, childOrigin, originForSending, destructor, log) => {
411
484
  const { destroy, onDestroy } = destructor;
412
485
  let destroyCallReceiver;
413
486
  let receiverMethodNames;
@@ -417,7 +490,7 @@ var handleAckMessageFactory = (methods, childOrigin, originForSending, destructo
417
490
  // latest provided by the child.
418
491
  const callSender = {};
419
492
  return (event) => {
420
- if (event.origin !== childOrigin) {
493
+ if (childOrigin !== '*' && event.origin !== childOrigin) {
421
494
  log(`Parent: Handshake - Received ACK message from origin ${event.origin} which did not match expected origin ${childOrigin}`);
422
495
  return;
423
496
  }
@@ -434,7 +507,7 @@ var handleAckMessageFactory = (methods, childOrigin, originForSending, destructo
434
507
  if (destroyCallReceiver) {
435
508
  destroyCallReceiver();
436
509
  }
437
- destroyCallReceiver = connectCallReceiver(info, methods, log);
510
+ destroyCallReceiver = connectCallReceiver(info, serializedMethods, log);
438
511
  onDestroy(destroyCallReceiver);
439
512
  // If the child reconnected, we need to remove the methods from the
440
513
  // previous call receiver off the sender.
@@ -453,16 +526,23 @@ var handleAckMessageFactory = (methods, childOrigin, originForSending, destructo
453
526
  /**
454
527
  * Handles a SYN handshake message.
455
528
  */
456
- var handleSynMessageFactory = (log, methods, childOrigin, originForSending) => {
529
+ var handleSynMessageFactory = (log, serializedMethods, childOrigin, originForSending) => {
457
530
  return (event) => {
458
- if (event.origin !== childOrigin) {
531
+ // Under specific timing circumstances, we can receive an event
532
+ // whose source is null. This seems to happen when the child iframe is
533
+ // removed from the DOM about the same time it has sent the SYN event.
534
+ // https://github.com/Aaronius/penpal/issues/85
535
+ if (!event.source) {
536
+ return;
537
+ }
538
+ if (childOrigin !== '*' && event.origin !== childOrigin) {
459
539
  log(`Parent: Handshake - Received SYN message from origin ${event.origin} which did not match expected origin ${childOrigin}`);
460
540
  return;
461
541
  }
462
542
  log('Parent: Handshake - Received SYN, responding with SYN-ACK');
463
543
  const synAckMessage = {
464
544
  penpal: MessageType.SynAck,
465
- methodNames: Object.keys(methods),
545
+ methodNames: Object.keys(serializedMethods),
466
546
  };
467
547
  event.source.postMessage(synAckMessage, originForSending);
468
548
  };
@@ -533,8 +613,9 @@ var connectToChild = (options) => {
533
613
  // must post messages with "*" as targetOrigin when sending messages.
534
614
  // https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage#Using_window.postMessage_in_extensions
535
615
  const originForSending = childOrigin === 'null' ? '*' : childOrigin;
536
- const handleSynMessage = handleSynMessageFactory(log, methods, childOrigin, originForSending);
537
- const handleAckMessage = handleAckMessageFactory(methods, childOrigin, originForSending, destructor, log);
616
+ const serializedMethods = serializeMethods(methods);
617
+ const handleSynMessage = handleSynMessageFactory(log, serializedMethods, childOrigin, originForSending);
618
+ const handleAckMessage = handleAckMessageFactory(serializedMethods, childOrigin, originForSending, destructor, log);
538
619
  const promise = new Promise((resolve, reject) => {
539
620
  const stopConnectionTimeout = startConnectionTimeout(timeout, destroy);
540
621
  const handleMessage = (event) => {
@@ -634,7 +715,7 @@ var insertIframe = function (id, importerDisplay) {
634
715
  return iframe;
635
716
  };
636
717
  var useCsvPlugin = function (_a) {
637
- var importerKey = _a.importerKey, user = _a.user, metadata = _a.metadata, onData = _a.onData, onRecordsInitial = _a.onRecordsInitial, onRecordEdit = _a.onRecordEdit, _b = _a.importerDisplay, importerDisplay = _b === void 0 ? "modal" : _b, onClose = _a.onClose, theme = _a.theme, batchSize = _a.batchSize;
718
+ var importerKey = _a.importerKey, user = _a.user, metadata = _a.metadata, onData = _a.onData, onRecordsInitial = _a.onRecordsInitial, onRecordEdit = _a.onRecordEdit, _b = _a.importerDisplay, importerDisplay = _b === void 0 ? "modal" : _b, onClose = _a.onClose, theme = _a.theme, batchSize = _a.batchSize, sampleFileURL = _a.sampleFileURL, _c = _a.downloadExampleButton, downloadExampleButton = _c === void 0 ? true : _c, dynamicColumns = _a.dynamicColumns;
638
719
  var id = "usecsv-".concat(Math.round(Math.random() * 100000000));
639
720
  return whenDomReady().then(function () {
640
721
  var iframe = insertIframe(id, importerDisplay);
@@ -666,7 +747,19 @@ var useCsvPlugin = function (_a) {
666
747
  var _a;
667
748
  (_a = document.getElementById(id)) === null || _a === void 0 ? void 0 : _a.classList.remove("loading");
668
749
  // eslint-disable-next-line dot-notation
669
- child["setParams"] && child["setParams"]({ importerKey: importerKey, user: user, metadata: metadata, importerDisplay: importerDisplay, theme: theme, batchSize: batchSize });
750
+ child["setParams"] &&
751
+ // eslint-disable-next-line dot-notation
752
+ child["setParams"]({
753
+ importerKey: importerKey,
754
+ user: user,
755
+ metadata: metadata,
756
+ importerDisplay: importerDisplay,
757
+ theme: theme,
758
+ batchSize: batchSize,
759
+ sampleFileURL: sampleFileURL,
760
+ downloadExampleButton: downloadExampleButton,
761
+ dynamicColumns: dynamicColumns,
762
+ });
670
763
  });
671
764
  return iframeConnection;
672
765
  });