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