@selkirk-systems/fetch 1.0.11 → 1.2.0

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/Fetch.js CHANGED
@@ -1,7 +1,9 @@
1
1
  //Inspired by https://www.bennadel.com/blog/4180-canceling-api-requests-using-fetch-and-abortcontroller-in-javascript.htm
2
2
 
3
3
  import Download from './Download';
4
+ import { DELETE_FROM_CACHE, UPDATE_CACHE } from './constants/FetchConstants';
4
5
  import FetchErrorHandler from './middleware/FetchErrorHandler';
6
+ import { dispatch, serializeData } from "@selkirk-systems/state-management";
5
7
 
6
8
  // Regular expression patterns for testing content-type response headers.
7
9
  const RE_CONTENT_TYPE_JSON = /^application\/(x-)?json/i;
@@ -12,6 +14,10 @@ const CONTENT_TYPE_DOWNLOADS = {
12
14
  'application/pdf': true,
13
15
  'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': true
14
16
  };
17
+
18
+ //30 minutes
19
+ const CACHED_EXPIRY_TIMESTAMP = 30 * 60000;
20
+
15
21
  //We store the original promise.catch so we can override it in some
16
22
  //scenarios when we want to swallow errors vs bubble them up.
17
23
  const ORIGINAL_CATCH_FN = Promise.prototype.catch;
@@ -44,6 +50,10 @@ export function OnOKResponse(fn) {
44
50
  return fn([network, isAbort]);
45
51
  };
46
52
  }
53
+ function isServiceWorker() {
54
+ return self;
55
+ }
56
+
47
57
  /**
48
58
  * Make the fetch request with the given configuration options.
49
59
  *
@@ -59,7 +69,7 @@ export function OnOKResponse(fn) {
59
69
  * - status.text
60
70
  * - status.isAbort
61
71
  */
62
- export default function Fetch(url, options = {}) {
72
+ function Fetch(url, options = {}) {
63
73
  const config = {
64
74
  downloadFileName: null,
65
75
  contentType: "application/json",
@@ -104,9 +114,11 @@ export default function Fetch(url, options = {}) {
104
114
  // For form data posts, we want the browser to build the Content-
105
115
  // Type for us so that it puts in both the "multipart/form-data" plus the
106
116
  // correct, auto-generated field delimiter.
107
- delete finalHeaders["content-type"];
108
- finalMethod = "POST";
109
- finalBody = buildFormData(config.form);
117
+ //delete ( finalHeaders["content-type"] );
118
+
119
+ //finalMethod = "POST";
120
+ //finalBody = buildFormData( config.form );
121
+ finalBody = config.form;
110
122
  } else if (config.json) {
111
123
  finalHeaders["content-type"] = config.contentType || "application/x-json";
112
124
  finalBody = JSON.stringify(config.json);
@@ -115,7 +127,7 @@ export default function Fetch(url, options = {}) {
115
127
  } else {
116
128
  finalHeaders["content-type"] = config.contentType;
117
129
  }
118
- request = new window.Request(finalUrl, {
130
+ request = new Request(finalUrl, {
119
131
  headers: finalHeaders,
120
132
  method: finalMethod,
121
133
  body: finalBody,
@@ -129,7 +141,7 @@ export default function Fetch(url, options = {}) {
129
141
 
130
142
  //Cache requests abort signal by url
131
143
  cacheRequestSignal(finalUrl, finalSignal);
132
- config._promiseChain = Promise.resolve(window.fetch(request)).then(async response => {
144
+ config._promiseChain = Promise.resolve(fetch(request)).then(async response => {
133
145
  deleteCachedRequestSignal(finalUrl);
134
146
  const data = await unwrapResponseData(response);
135
147
  if (response.ok) {
@@ -287,7 +299,12 @@ function buildFormData(form) {
287
299
  function buildURL(url, templateData, params) {
288
300
  if (url.href) return url;
289
301
  const formattedUrl = buildURLTemplate(url, templateData);
290
- const finalUrl = new URL(formattedUrl, `${window.location.origin}${window.baseUrl || ""}`);
302
+ let finalUrl;
303
+ if (self) {
304
+ finalUrl = new URL(formattedUrl);
305
+ } else {
306
+ finalUrl = new URL(formattedUrl, `${window.location.origin}${window.baseUrl || ""}`);
307
+ }
291
308
  const searchParams = new URLSearchParams();
292
309
  Object.entries(params).forEach(([key, value]) => {
293
310
  if (Array.isArray(value)) {
@@ -403,4 +420,110 @@ function normalizeTransportError(transportError, request, config) {
403
420
  isAbort: isAbort
404
421
  }
405
422
  };
406
- }
423
+ }
424
+ const responseObjectJson = {
425
+ status: 200,
426
+ headers: {
427
+ 'Content-Type': 'application/json'
428
+ }
429
+ };
430
+ export const getCacheByName = async name => {
431
+ try {
432
+ return caches.open(name);
433
+ } catch (err) {
434
+ throw err;
435
+ }
436
+ };
437
+ export const putJsonInCache = (cache, url, json) => {
438
+ const response = new Response(JSON.stringify(json), responseObjectJson);
439
+ return cache.put(url, response);
440
+ };
441
+ let _cache = null;
442
+ const DATA_METHODS = {
443
+ "GET": null,
444
+ "PATCH": null,
445
+ "POST": null,
446
+ "PUT": null
447
+ };
448
+ const _fetch = (url, options = {}) => {
449
+ if (self) {
450
+ return Fetch(url, options);
451
+ }
452
+ function cacheResponse([response, isAbort]) {
453
+ const status = response.status.code;
454
+ const headers = response.request.headers;
455
+ const method = response.request.method;
456
+ if (status >= 200 && status < 400 && headers.get('content-type') === "application/json") {
457
+ if (DATA_METHODS.hasOwnProperty(method) || method === "GET") {
458
+ const data = serializeData(response.data);
459
+ if (data.page && !data.items || data.items && data.items.length === 0) {
460
+ deleteFromCache(_cache, url, response);
461
+ return [response, isAbort];
462
+ }
463
+ const finalOptions = {
464
+ ...responseObjectJson
465
+ };
466
+ finalOptions.headers['Time-Cached'] = new Date().getTime();
467
+ const responseObj = new Response(JSON.stringify(response), finalOptions);
468
+ _cache.put(url, responseObj);
469
+ dispatch(UPDATE_CACHE, {
470
+ url: url,
471
+ response: response
472
+ });
473
+ return [response, isAbort];
474
+ }
475
+ if (method === "DELETE") {
476
+ deleteFromCache(_cache, url, response);
477
+ return [response, isAbort];
478
+ }
479
+ }
480
+ return [response, isAbort];
481
+ }
482
+ function cacheMatch() {
483
+ //HANDLE: Data updates, always return fresh data
484
+ if (options.method && DATA_METHODS.hasOwnProperty(options.method)) {
485
+ return Fetch(url, options).then(cacheResponse);
486
+ }
487
+ return _cache.match(url).then(response => {
488
+ if (response) {
489
+ const timeCached = response.headers.get('Time-Cached');
490
+ if (expiredCache(timeCached)) {
491
+ _cache.delete(url);
492
+ return Fetch(url, options).then(cacheResponse);
493
+ }
494
+ Fetch(url, options).then(cacheResponse);
495
+ return unwrapResponseData(response).then(obj => {
496
+ return Promise.resolve([{
497
+ request: null,
498
+ response: response,
499
+ data: obj.data,
500
+ status: {
501
+ code: response.status,
502
+ text: response.statusText,
503
+ isAbort: false
504
+ }
505
+ }, false]);
506
+ });
507
+ }
508
+ return Fetch(url, options).then(cacheResponse);
509
+ });
510
+ }
511
+ if (_cache) {
512
+ return cacheMatch();
513
+ }
514
+ return caches.open('fetch').then(cache => {
515
+ _cache = cache;
516
+ }).then(cacheMatch);
517
+ };
518
+ function deleteFromCache(_cache, url, response) {
519
+ _cache.delete(url);
520
+ dispatch(DELETE_FROM_CACHE, {
521
+ url: url,
522
+ response: response
523
+ });
524
+ }
525
+ function expiredCache(timeCached) {
526
+ const now = new Date().getTime();
527
+ return Math.abs(now - timeCached) >= CACHED_EXPIRY_TIMESTAMP;
528
+ }
529
+ export default _fetch;
@@ -0,0 +1,3 @@
1
+ export const ADD_ERROR = "ADD_ERROR";
2
+ export const UPDATE_CACHE = "UPDATE_CACHE";
3
+ export const DELETE_FROM_CACHE = "DELETE_FROM_CACHE";
package/dist/index.js CHANGED
@@ -1,3 +1,3 @@
1
1
  export { default as Download } from './Download';
2
2
  export { default as fetch, applyMiddleware, OnOKResponse } from './Fetch';
3
- export { ADD_ERROR } from "./constants/ErrorConstants";
3
+ export * from "./constants/FetchConstants";
@@ -1,5 +1,5 @@
1
1
  import { dispatch } from "@selkirk-systems/state-management";
2
- import { ADD_ERROR } from "../constants/ErrorConstants";
2
+ import { ADD_ERROR } from "../constants/FetchConstants";
3
3
  const handler = err => response => options => next => {
4
4
  if (err) {
5
5
  dispatch(ADD_ERROR, err);
@@ -8,30 +8,33 @@ const handler = err => response => options => next => {
8
8
  return next(null, response);
9
9
  };
10
10
 
11
- // NOTE: event name is all lower case as per DOM convention
12
- window.addEventListener("unhandledrejection", function (e) {
13
- // NOTE: e.preventDefault() must be manually called to prevent the default
14
- // action which is currently to log the stack trace to console.warn
15
- e.preventDefault();
16
- // NOTE: parameters are properties of the event detail property
17
- var reason = e.reason || e.detail.reason;
18
- //var promise = e.detail.promise;
19
- // See Promise.onPossiblyUnhandledRejection for parameter documentation
20
- console.groupEnd();
21
- console.groupEnd();
22
- console.groupEnd();
23
- throw reason;
24
- });
11
+ //HANDLE: Not being called from a service worker
12
+ if (!self) {
13
+ // NOTE: event name is all lower case as per DOM convention
14
+ window.addEventListener("unhandledrejection", function (e) {
15
+ // NOTE: e.preventDefault() must be manually called to prevent the default
16
+ // action which is currently to log the stack trace to console.warn
17
+ e.preventDefault();
18
+ // NOTE: parameters are properties of the event detail property
19
+ var reason = e.reason || e.detail.reason;
20
+ //var promise = e.detail.promise;
21
+ // See Promise.onPossiblyUnhandledRejection for parameter documentation
22
+ console.groupEnd();
23
+ console.groupEnd();
24
+ console.groupEnd();
25
+ throw reason;
26
+ });
25
27
 
26
- // NOTE: event name is all lower case as per DOM convention
27
- window.addEventListener("rejectionhandled", function (e) {
28
- // NOTE: e.preventDefault() must be manually called prevent the default
29
- // action which is currently unset (but might be set to something in the future)
30
- e.preventDefault();
31
- // NOTE: parameters are properties of the event detail property
32
- var promise = e.reason || e.detail.promise;
33
- // See Promise.onUnhandledRejectionHandled for parameter documentation
34
- console.groupEnd();
35
- console.log("REJECTION HANDLED", promise);
36
- });
28
+ // NOTE: event name is all lower case as per DOM convention
29
+ window.addEventListener("rejectionhandled", function (e) {
30
+ // NOTE: e.preventDefault() must be manually called prevent the default
31
+ // action which is currently unset (but might be set to something in the future)
32
+ e.preventDefault();
33
+ // NOTE: parameters are properties of the event detail property
34
+ var promise = e.reason || e.detail.promise;
35
+ // See Promise.onUnhandledRejectionHandled for parameter documentation
36
+ console.groupEnd();
37
+ console.log("REJECTION HANDLED", promise);
38
+ });
39
+ }
37
40
  export default handler;
package/lib/Fetch.js CHANGED
@@ -1,7 +1,9 @@
1
1
  //Inspired by https://www.bennadel.com/blog/4180-canceling-api-requests-using-fetch-and-abortcontroller-in-javascript.htm
2
2
 
3
3
  import Download from './Download';
4
+ import { DELETE_FROM_CACHE, UPDATE_CACHE } from './constants/FetchConstants';
4
5
  import FetchErrorHandler from './middleware/FetchErrorHandler';
6
+ import { dispatch, serializeData } from "@selkirk-systems/state-management";
5
7
 
6
8
  // Regular expression patterns for testing content-type response headers.
7
9
  const RE_CONTENT_TYPE_JSON = /^application\/(x-)?json/i;
@@ -14,6 +16,10 @@ const CONTENT_TYPE_DOWNLOADS = {
14
16
  'application/pdf': true,
15
17
  'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': true
16
18
  }
19
+
20
+ //30 minutes
21
+ const CACHED_EXPIRY_TIMESTAMP = 30 * 60000;
22
+
17
23
  //We store the original promise.catch so we can override it in some
18
24
  //scenarios when we want to swallow errors vs bubble them up.
19
25
  const ORIGINAL_CATCH_FN = Promise.prototype.catch;
@@ -51,6 +57,12 @@ export function OnOKResponse( fn ) {
51
57
  return fn( [network, isAbort] );
52
58
  }
53
59
  }
60
+
61
+ function isServiceWorker() {
62
+ return self;
63
+ }
64
+
65
+
54
66
  /**
55
67
  * Make the fetch request with the given configuration options.
56
68
  *
@@ -66,7 +78,7 @@ export function OnOKResponse( fn ) {
66
78
  * - status.text
67
79
  * - status.isAbort
68
80
  */
69
- export default function Fetch( url, options = {} ) {
81
+ function Fetch( url, options = {} ) {
70
82
 
71
83
  const config = {
72
84
  downloadFileName: null,
@@ -121,10 +133,11 @@ export default function Fetch( url, options = {} ) {
121
133
  // For form data posts, we want the browser to build the Content-
122
134
  // Type for us so that it puts in both the "multipart/form-data" plus the
123
135
  // correct, auto-generated field delimiter.
124
- delete ( finalHeaders["content-type"] );
136
+ //delete ( finalHeaders["content-type"] );
125
137
 
126
- finalMethod = "POST";
127
- finalBody = buildFormData( config.form );
138
+ //finalMethod = "POST";
139
+ //finalBody = buildFormData( config.form );
140
+ finalBody = config.form;
128
141
 
129
142
  } else if ( config.json ) {
130
143
 
@@ -140,7 +153,7 @@ export default function Fetch( url, options = {} ) {
140
153
  finalHeaders["content-type"] = config.contentType;
141
154
  }
142
155
 
143
- request = new window.Request(
156
+ request = new Request(
144
157
  finalUrl,
145
158
  {
146
159
  headers: finalHeaders,
@@ -158,7 +171,7 @@ export default function Fetch( url, options = {} ) {
158
171
  //Cache requests abort signal by url
159
172
  cacheRequestSignal( finalUrl, finalSignal );
160
173
 
161
- config._promiseChain = Promise.resolve( window.fetch( request ) )
174
+ config._promiseChain = Promise.resolve( fetch( request ) )
162
175
  .then( async ( response ) => {
163
176
 
164
177
  deleteCachedRequestSignal( finalUrl );
@@ -381,8 +394,14 @@ function buildURL( url, templateData, params ) {
381
394
  if ( url.href ) return url;
382
395
 
383
396
  const formattedUrl = buildURLTemplate( url, templateData );
397
+ let finalUrl;
384
398
 
385
- const finalUrl = new URL( formattedUrl, `${window.location.origin}${window.baseUrl || ""}` );
399
+ if ( self ) {
400
+ finalUrl = new URL( formattedUrl );
401
+ }
402
+ else {
403
+ finalUrl = new URL( formattedUrl, `${window.location.origin}${window.baseUrl || ""}` );
404
+ }
386
405
 
387
406
  const searchParams = new URLSearchParams();
388
407
 
@@ -529,4 +548,159 @@ function normalizeTransportError( transportError, request, config ) {
529
548
  }
530
549
  } );
531
550
 
532
- }
551
+ }
552
+
553
+ const responseObjectJson = {
554
+ status: 200,
555
+ headers: {
556
+ 'Content-Type': 'application/json'
557
+ }
558
+ }
559
+
560
+ export const getCacheByName = async ( name ) => {
561
+ try {
562
+ return caches.open( name );
563
+ } catch ( err ) {
564
+ throw ( err );
565
+ }
566
+ }
567
+
568
+
569
+ export const putJsonInCache = ( cache, url, json ) => {
570
+
571
+ const response = new Response( JSON.stringify( json ), responseObjectJson );
572
+
573
+ return cache.put( url, response )
574
+
575
+ }
576
+
577
+ let _cache = null;
578
+ const DATA_METHODS = {
579
+ "GET": null,
580
+ "PATCH": null,
581
+ "POST": null,
582
+ "PUT": null
583
+ }
584
+
585
+ const _fetch = ( url, options = {} ) => {
586
+
587
+ if ( self ) {
588
+ return Fetch( url, options );
589
+ }
590
+
591
+ function cacheResponse( [response, isAbort] ) {
592
+
593
+ const status = response.status.code;
594
+ const headers = response.request.headers;
595
+ const method = response.request.method;
596
+
597
+
598
+ if ( status >= 200 && status < 400 && headers.get( 'content-type' ) === "application/json" ) {
599
+
600
+ if ( DATA_METHODS.hasOwnProperty( method ) || method === "GET" ) {
601
+
602
+ const data = serializeData( response.data );
603
+
604
+ if ( data.page && !data.items || data.items && data.items.length === 0 ) {
605
+
606
+ deleteFromCache( _cache, url, response );
607
+
608
+ return [response, isAbort];
609
+
610
+ }
611
+
612
+ const finalOptions = { ...responseObjectJson };
613
+ finalOptions.headers['Time-Cached'] = new Date().getTime();
614
+
615
+ const responseObj = new Response( JSON.stringify( response ), finalOptions );
616
+ _cache.put( url, responseObj );
617
+
618
+ dispatch( UPDATE_CACHE, { url: url, response: response } );
619
+
620
+ return [response, isAbort];
621
+ }
622
+
623
+ if ( method === "DELETE" ) {
624
+
625
+ deleteFromCache( _cache, url, response );
626
+ return [response, isAbort];
627
+
628
+ }
629
+
630
+
631
+ }
632
+
633
+ return [response, isAbort];
634
+
635
+ }
636
+
637
+ function cacheMatch() {
638
+
639
+ //HANDLE: Data updates, always return fresh data
640
+ if ( options.method && DATA_METHODS.hasOwnProperty( options.method ) ) {
641
+
642
+ return Fetch( url, options ).then( cacheResponse );
643
+
644
+ }
645
+
646
+
647
+ return _cache.match( url ).then( ( response ) => {
648
+
649
+ if ( response ) {
650
+
651
+ const timeCached = response.headers.get( 'Time-Cached' );
652
+
653
+ if ( expiredCache( timeCached ) ) {
654
+
655
+ _cache.delete( url );
656
+ return Fetch( url, options ).then( cacheResponse );
657
+
658
+ }
659
+
660
+ Fetch( url, options ).then( cacheResponse )
661
+
662
+ return unwrapResponseData( response ).then( ( obj ) => {
663
+ return Promise.resolve( [{
664
+ request: null,
665
+ response: response,
666
+ data: obj.data,
667
+ status: {
668
+ code: response.status,
669
+ text: response.statusText,
670
+ isAbort: false
671
+ },
672
+ }, false] )
673
+ } )
674
+
675
+
676
+ }
677
+
678
+ return Fetch( url, options ).then( cacheResponse );
679
+ } )
680
+ }
681
+
682
+ if ( _cache ) {
683
+
684
+ return cacheMatch()
685
+ }
686
+
687
+ return caches.open( 'fetch' ).then( ( cache ) => {
688
+ _cache = cache;
689
+ } ).then( cacheMatch )
690
+
691
+ }
692
+
693
+ function deleteFromCache( _cache, url, response ) {
694
+
695
+ _cache.delete( url );
696
+ dispatch( DELETE_FROM_CACHE, { url: url, response: response } );
697
+
698
+ }
699
+
700
+ function expiredCache( timeCached ) {
701
+ const now = new Date().getTime();
702
+
703
+ return Math.abs( now - timeCached ) >= CACHED_EXPIRY_TIMESTAMP;
704
+ }
705
+
706
+ export default _fetch;
@@ -0,0 +1,3 @@
1
+ export const ADD_ERROR = "ADD_ERROR";
2
+ export const UPDATE_CACHE = "UPDATE_CACHE";
3
+ export const DELETE_FROM_CACHE = "DELETE_FROM_CACHE";
package/lib/index.js CHANGED
@@ -1,3 +1,3 @@
1
1
  export { default as Download } from './Download';
2
2
  export { default as fetch, applyMiddleware, OnOKResponse } from './Fetch';
3
- export { ADD_ERROR } from "./constants/ErrorConstants";
3
+ export * from "./constants/FetchConstants";
@@ -1,5 +1,5 @@
1
1
  import { dispatch } from "@selkirk-systems/state-management";
2
- import { ADD_ERROR } from "../constants/ErrorConstants";
2
+ import { ADD_ERROR } from "../constants/FetchConstants";
3
3
 
4
4
  const handler = ( err ) => ( response ) => ( options ) => ( next ) => {
5
5
  if ( err ) {
@@ -11,32 +11,35 @@ const handler = ( err ) => ( response ) => ( options ) => ( next ) => {
11
11
  return next( null, response );
12
12
  };
13
13
 
14
- // NOTE: event name is all lower case as per DOM convention
15
- window.addEventListener( "unhandledrejection", function ( e ) {
16
- // NOTE: e.preventDefault() must be manually called to prevent the default
17
- // action which is currently to log the stack trace to console.warn
18
- e.preventDefault();
19
- // NOTE: parameters are properties of the event detail property
20
- var reason = e.reason || e.detail.reason;
21
- //var promise = e.detail.promise;
22
- // See Promise.onPossiblyUnhandledRejection for parameter documentation
23
- console.groupEnd();
24
- console.groupEnd();
25
- console.groupEnd();
26
- throw reason;
27
- } );
14
+ //HANDLE: Not being called from a service worker
15
+ if ( !self ) {
16
+ // NOTE: event name is all lower case as per DOM convention
17
+ window.addEventListener( "unhandledrejection", function ( e ) {
18
+ // NOTE: e.preventDefault() must be manually called to prevent the default
19
+ // action which is currently to log the stack trace to console.warn
20
+ e.preventDefault();
21
+ // NOTE: parameters are properties of the event detail property
22
+ var reason = e.reason || e.detail.reason;
23
+ //var promise = e.detail.promise;
24
+ // See Promise.onPossiblyUnhandledRejection for parameter documentation
25
+ console.groupEnd();
26
+ console.groupEnd();
27
+ console.groupEnd();
28
+ throw reason;
29
+ } );
28
30
 
29
- // NOTE: event name is all lower case as per DOM convention
30
- window.addEventListener( "rejectionhandled", function ( e ) {
31
- // NOTE: e.preventDefault() must be manually called prevent the default
32
- // action which is currently unset (but might be set to something in the future)
33
- e.preventDefault();
34
- // NOTE: parameters are properties of the event detail property
35
- var promise = e.reason || e.detail.promise;
36
- // See Promise.onUnhandledRejectionHandled for parameter documentation
37
- console.groupEnd();
38
- console.log( "REJECTION HANDLED", promise );
39
- } );
31
+ // NOTE: event name is all lower case as per DOM convention
32
+ window.addEventListener( "rejectionhandled", function ( e ) {
33
+ // NOTE: e.preventDefault() must be manually called prevent the default
34
+ // action which is currently unset (but might be set to something in the future)
35
+ e.preventDefault();
36
+ // NOTE: parameters are properties of the event detail property
37
+ var promise = e.reason || e.detail.promise;
38
+ // See Promise.onUnhandledRejectionHandled for parameter documentation
39
+ console.groupEnd();
40
+ console.log( "REJECTION HANDLED", promise );
41
+ } );
42
+ }
40
43
 
41
44
  export default handler;
42
45
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@selkirk-systems/fetch",
3
- "version": "1.0.11",
3
+ "version": "1.2.0",
4
4
  "description": "Abortable fetch library",
5
5
  "keywords": [],
6
6
  "author": "Marcos Bernal <mbernal@selkirksystems.com>",
@@ -36,5 +36,5 @@
36
36
  "peerDependencies": {
37
37
  "@selkirk-systems/state-management": ">=1.0.0"
38
38
  },
39
- "gitHead": "9bd782d38d100b8be6ca48a23bbf2532a6b8d584"
39
+ "gitHead": "5898e1276808bd3fe25d44f3935befe00c54513e"
40
40
  }
@@ -1 +0,0 @@
1
- export const ADD_ERROR = "ADD_ERROR";