@thoughtbot/superglue 1.0.3 → 2.0.0-alpha.10

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.
@@ -179,7 +179,26 @@ var config = {
179
179
  maxPages: 20
180
180
  };
181
181
 
182
+ // lib/utils/limited_set.ts
183
+ var LimitedSet = class extends Set {
184
+ constructor(maxSize) {
185
+ super();
186
+ this.maxSize = maxSize;
187
+ }
188
+ add(value) {
189
+ if (this.size >= this.maxSize) {
190
+ const iterator = this.values();
191
+ const oldestValue = iterator.next().value;
192
+ this.delete(oldestValue);
193
+ }
194
+ super.add(value);
195
+ return this;
196
+ }
197
+ };
198
+
182
199
  // lib/utils/request.ts
200
+ import { v4 as uuidv4 } from "uuid";
201
+ var lastRequestIds = new LimitedSet(20);
183
202
  function isValidResponse(xhr) {
184
203
  return isValidContent(xhr) && !downloadingFile(xhr);
185
204
  }
@@ -235,6 +254,9 @@ function argsForFetch(getState, pathQuery2, {
235
254
  nextHeaders["x-requested-with"] = "XMLHttpRequest";
236
255
  nextHeaders["accept"] = "application/json";
237
256
  nextHeaders["x-superglue-request"] = "true";
257
+ const requestId = uuidv4();
258
+ lastRequestIds.add(requestId);
259
+ nextHeaders["X-Superglue-Request-Id"] = requestId;
238
260
  if (method != "GET" && method != "HEAD") {
239
261
  nextHeaders["content-type"] = "application/json";
240
262
  }
@@ -274,7 +296,7 @@ function argsForFetch(getState, pathQuery2, {
274
296
  return [fetchPath.toString(), { ...options, ...rest }];
275
297
  }
276
298
  function extractJSON(rsp) {
277
- return rsp.clone().json().then((json) => {
299
+ return rsp.json().then((json) => {
278
300
  return { rsp, json };
279
301
  }).catch((e) => {
280
302
  e.response = rsp;
@@ -428,7 +450,6 @@ var handleGraft = createAction(
428
450
  var superglueError = createAction(
429
451
  "@@superglue/ERROR"
430
452
  );
431
- var updateFragments = createAction("@@superglue/UPDATE_FRAGMENTS");
432
453
  var copyPage = createAction(
433
454
  "@@superglue/COPY_PAGE"
434
455
  );
@@ -443,24 +464,291 @@ var beforeRemote = createAction("@@superglue/BEFORE_REMOTE");
443
464
  var setCSRFToken = createAction("@@superglue/SET_CSRF_TOKEN");
444
465
  var historyChange = createAction("@@superglue/HISTORY_CHANGE");
445
466
  var setActivePage = createAction("@@superglue/SET_ACTIVE_PAGE");
467
+ var handleFragmentGraft = createAction(
468
+ "@@superglue/HANDLE_FRAGMENT_GRAFT",
469
+ ({
470
+ fragmentId,
471
+ response
472
+ }) => {
473
+ return {
474
+ payload: {
475
+ response,
476
+ fragmentId
477
+ }
478
+ };
479
+ }
480
+ );
481
+ var saveFragment = createAction(
482
+ "@@superglue/SAVE_FRAGMENT",
483
+ ({ fragmentId, data }) => {
484
+ return {
485
+ payload: {
486
+ fragmentId,
487
+ data
488
+ }
489
+ };
490
+ }
491
+ );
492
+ var receiveResponse = createAction(
493
+ "@@superglue/RECEIVE_RESPONSE",
494
+ ({ pageKey, response }) => {
495
+ pageKey = urlToPageKey(pageKey);
496
+ return {
497
+ payload: {
498
+ pageKey,
499
+ response
500
+ }
501
+ };
502
+ }
503
+ );
504
+ var appendToFragment = createAction(
505
+ "@@superglue/APPEND_TO_FRAGMENT",
506
+ ({ data, fragmentId }) => {
507
+ return {
508
+ payload: {
509
+ data,
510
+ fragmentId
511
+ }
512
+ };
513
+ }
514
+ );
515
+ var prependToFragment = createAction(
516
+ "@@superglue/PREPEND_TO_FRAGMENT",
517
+ ({ data, fragmentId }) => {
518
+ return {
519
+ payload: {
520
+ data,
521
+ fragmentId
522
+ }
523
+ };
524
+ }
525
+ );
526
+
527
+ // lib/utils/proxy.ts
528
+ var ORIGINAL_TARGET = Symbol("@@originalTarget");
529
+ var ARRAY_GETTER_METHODS = /* @__PURE__ */ new Set([
530
+ Symbol.iterator,
531
+ "at",
532
+ "concat",
533
+ "entries",
534
+ "every",
535
+ "filter",
536
+ "find",
537
+ "findIndex",
538
+ "flat",
539
+ "flatMap",
540
+ "forEach",
541
+ "includes",
542
+ "indexOf",
543
+ "join",
544
+ "keys",
545
+ "lastIndexOf",
546
+ "map",
547
+ "reduce",
548
+ "reduceRight",
549
+ "slice",
550
+ "some",
551
+ "toString",
552
+ "values"
553
+ ]);
554
+ var ARRAY_SETTER_METHODS = /* @__PURE__ */ new Set([
555
+ "copyWithin",
556
+ "fill",
557
+ "pop",
558
+ "push",
559
+ "reverse",
560
+ "shift",
561
+ "sort",
562
+ "splice",
563
+ "unshift"
564
+ ]);
565
+ function isArraySetter(prop) {
566
+ return ARRAY_SETTER_METHODS.has(prop);
567
+ }
568
+ function isArrayGetter(prop) {
569
+ return ARRAY_GETTER_METHODS.has(prop);
570
+ }
571
+ function convertToInt(prop) {
572
+ if (typeof prop === "symbol") return null;
573
+ const num = Number(prop);
574
+ return Number.isInteger(num) ? num : null;
575
+ }
576
+ function isFragmentReference(value) {
577
+ return !!value && typeof value === "object" && "__id" in value && typeof value.__id === "string";
578
+ }
579
+ function createArrayProxy(arrayData, fragments, dependencies, proxyCache) {
580
+ if (proxyCache && proxyCache.has(arrayData)) {
581
+ return proxyCache.get(arrayData);
582
+ }
583
+ const proxy = new Proxy(arrayData, {
584
+ get(target, prop) {
585
+ if (prop === ORIGINAL_TARGET) {
586
+ return target;
587
+ }
588
+ if (isArrayGetter(prop)) {
589
+ const method = target[prop];
590
+ if (typeof method === "function") {
591
+ return function(...args) {
592
+ return Reflect.apply(method, proxy, args);
593
+ };
594
+ }
595
+ return method;
596
+ }
597
+ if (isArraySetter(prop)) {
598
+ throw new Error(
599
+ `Cannot mutate proxy array. Use useSetFragment to update state.`
600
+ );
601
+ }
602
+ const index = convertToInt(prop);
603
+ if (index !== null && index >= 0 && index < target.length) {
604
+ const item = target[index];
605
+ if (isFragmentReference(item)) {
606
+ dependencies.add(item.__id);
607
+ const fragmentData = fragments.current[item.__id];
608
+ if (!fragmentData) {
609
+ return void 0;
610
+ }
611
+ return createProxy(fragmentData, fragments, dependencies, proxyCache);
612
+ }
613
+ if (typeof item === "object" && item !== null) {
614
+ if ("$$typeof" in item) {
615
+ return item;
616
+ } else {
617
+ return createProxy(
618
+ item,
619
+ fragments,
620
+ dependencies,
621
+ proxyCache
622
+ );
623
+ }
624
+ }
625
+ return item;
626
+ }
627
+ return Reflect.get(target, prop);
628
+ },
629
+ has(target, prop) {
630
+ if (prop === ORIGINAL_TARGET) {
631
+ return true;
632
+ }
633
+ return Reflect.has(target, prop);
634
+ },
635
+ set() {
636
+ throw new Error(
637
+ "Cannot mutate proxy array. Use useSetFragment to update state."
638
+ );
639
+ },
640
+ deleteProperty() {
641
+ throw new Error(
642
+ "Cannot delete properties on proxy array. Use useSetFragment to update state."
643
+ );
644
+ },
645
+ defineProperty() {
646
+ throw new Error(
647
+ "Cannot define properties on proxy array. Use useSetFragment to update state."
648
+ );
649
+ }
650
+ });
651
+ if (proxyCache) {
652
+ proxyCache.set(arrayData, proxy);
653
+ }
654
+ return proxy;
655
+ }
656
+ function createObjectProxy(objectData, fragments, dependencies, proxyCache) {
657
+ if (proxyCache && proxyCache.has(objectData)) {
658
+ return proxyCache.get(objectData);
659
+ }
660
+ const proxy = new Proxy(objectData, {
661
+ get(target, prop) {
662
+ if (prop === ORIGINAL_TARGET) {
663
+ return target;
664
+ }
665
+ const value = target[prop];
666
+ if (isFragmentReference(value)) {
667
+ dependencies.add(value.__id);
668
+ const fragmentData = fragments.current[value.__id];
669
+ if (!fragmentData) {
670
+ return void 0;
671
+ }
672
+ return createProxy(fragmentData, fragments, dependencies, proxyCache);
673
+ }
674
+ if (typeof value === "object" && value !== null) {
675
+ if ("$$typeof" in value) {
676
+ return value;
677
+ } else if (Array.isArray(value)) {
678
+ return createArrayProxy(value, fragments, dependencies, proxyCache);
679
+ } else {
680
+ return createObjectProxy(value, fragments, dependencies, proxyCache);
681
+ }
682
+ }
683
+ return value;
684
+ },
685
+ has(target, prop) {
686
+ if (prop === ORIGINAL_TARGET) {
687
+ return true;
688
+ }
689
+ return Reflect.has(target, prop);
690
+ },
691
+ set() {
692
+ throw new Error(
693
+ "Cannot mutate proxy object. Use useSetFragment to update state."
694
+ );
695
+ },
696
+ deleteProperty() {
697
+ throw new Error(
698
+ "Cannot delete properties on proxy object. Use useSetFragment to update state."
699
+ );
700
+ },
701
+ defineProperty() {
702
+ throw new Error(
703
+ "Cannot define properties on proxy object. Use useSetFragment to update state."
704
+ );
705
+ }
706
+ });
707
+ if (proxyCache) {
708
+ proxyCache.set(objectData, proxy);
709
+ }
710
+ return proxy;
711
+ }
712
+ function createProxy(content, fragments, dependencies, proxyCache) {
713
+ if (!content || typeof content !== "object") {
714
+ return content;
715
+ }
716
+ if ("$$typeof" in content) {
717
+ return content;
718
+ }
719
+ if (Array.isArray(content)) {
720
+ return createArrayProxy(content, fragments, dependencies, proxyCache);
721
+ }
722
+ return createObjectProxy(content, fragments, dependencies, proxyCache);
723
+ }
724
+ function unproxy(proxy) {
725
+ if (proxy && typeof proxy === "object" && ORIGINAL_TARGET in proxy) {
726
+ return proxy[ORIGINAL_TARGET];
727
+ }
728
+ return proxy;
729
+ }
446
730
 
447
731
  // lib/action_creators/requests.ts
448
732
  function handleFetchErr(err, fetchArgs, dispatch) {
449
733
  dispatch(superglueError({ message: err.message }));
734
+ console.error(err);
450
735
  throw err;
451
736
  }
452
737
  function buildMeta(pageKey, page, state, rsp, fetchArgs) {
453
738
  const { assets: prevAssets } = state;
454
739
  const { assets: nextAssets } = page;
455
- return {
740
+ const meta = {
456
741
  pageKey,
457
742
  page,
458
743
  redirected: rsp.redirected,
459
744
  rsp,
460
745
  fetchArgs,
461
- componentIdentifier: page.componentIdentifier,
462
746
  needsRefresh: needsRefresh(prevAssets, nextAssets)
463
747
  };
748
+ if (page.action !== "handleStreamResponse") {
749
+ meta.componentIdentifier = page.componentIdentifier;
750
+ }
751
+ return meta;
464
752
  }
465
753
  var MismatchedComponentError = class extends Error {
466
754
  constructor(message) {
@@ -468,10 +756,11 @@ var MismatchedComponentError = class extends Error {
468
756
  this.name = "MismatchedComponentError";
469
757
  }
470
758
  };
759
+ var defaultBeforeSave = (prevPage, receivedPage) => receivedPage;
471
760
  var remote = (path, {
472
761
  pageKey: targetPageKey,
473
762
  force = false,
474
- beforeSave = (prevPage, receivedPage) => receivedPage,
763
+ beforeSave = defaultBeforeSave,
475
764
  ...rest
476
765
  } = {}) => {
477
766
  targetPageKey = targetPageKey && urlToPageKey(targetPageKey);
@@ -481,7 +770,7 @@ var remote = (path, {
481
770
  dispatch(beforeRemote({ currentPageKey, fetchArgs }));
482
771
  dispatch(beforeFetch({ fetchArgs }));
483
772
  return fetch(...fetchArgs).then(parseResponse).then(({ rsp, json }) => {
484
- const { superglue, pages = {} } = getState();
773
+ const { superglue, pages = {}, fragments } = getState();
485
774
  let pageKey;
486
775
  if (targetPageKey === void 0) {
487
776
  const isGet = fetchArgs[1].method === "GET";
@@ -490,10 +779,11 @@ var remote = (path, {
490
779
  pageKey = targetPageKey;
491
780
  }
492
781
  const meta = buildMeta(pageKey, json, superglue, rsp, fetchArgs);
493
- const existingId = pages[pageKey]?.componentIdentifier;
494
- const receivedId = json.componentIdentifier;
495
- if (!!existingId && existingId != receivedId && !force) {
496
- const message = `You cannot replace or update an existing page
782
+ if (json.action !== "handleStreamResponse") {
783
+ const existingId = pages[pageKey]?.componentIdentifier;
784
+ const receivedId = json.componentIdentifier;
785
+ if (!!existingId && existingId != receivedId && !force) {
786
+ const message = `You cannot replace or update an existing page
497
787
  located at pages["${currentPageKey}"] that has a componentIdentifier
498
788
  of "${existingId}" with the contents of a page response that has a
499
789
  componentIdentifier of "${receivedId}".
@@ -509,9 +799,27 @@ compatible with the page component associated with "${existingId}".
509
799
  Consider using data-sg-visit, the visit function, or redirect_back to
510
800
  the same page. Or if you're sure you want to proceed, use force: true.
511
801
  `;
512
- throw new MismatchedComponentError(message);
802
+ throw new MismatchedComponentError(message);
803
+ }
804
+ }
805
+ dispatch(
806
+ receiveResponse({
807
+ pageKey,
808
+ response: JSON.parse(JSON.stringify(json))
809
+ })
810
+ );
811
+ const existingPage = createProxy(
812
+ pages[pageKey],
813
+ { current: fragments },
814
+ /* @__PURE__ */ new Set(),
815
+ /* @__PURE__ */ new WeakMap()
816
+ );
817
+ let page = json;
818
+ if (json.action === "savePage" || json.action === "graft") {
819
+ page = JSON.parse(
820
+ JSON.stringify(beforeSave(existingPage, json))
821
+ );
513
822
  }
514
- const page = beforeSave(pages[pageKey], json);
515
823
  return dispatch(saveAndProcessPage(pageKey, page)).then(() => meta);
516
824
  }).catch((e) => handleFetchErr(e, fetchArgs, dispatch));
517
825
  };
@@ -550,14 +858,16 @@ var visit = (path, {
550
858
  );
551
859
  lastVisitController = controller;
552
860
  return fetch(...fetchArgs).then(parseResponse).then(({ rsp, json }) => {
553
- const { superglue, pages = {} } = getState();
861
+ const { superglue, pages = {}, fragments } = getState();
554
862
  const isGet = fetchArgs[1].method === "GET";
555
863
  const pageKey = calculatePageKey(rsp, isGet, currentPageKey);
556
- if (placeholderKey && hasPropsAt(path) && hasPlaceholder) {
557
- const existingId = pages[placeholderKey]?.componentIdentifier;
558
- const receivedId = json.componentIdentifier;
559
- if (!!existingId && existingId != receivedId) {
560
- const message = `You received a page response with a
864
+ const meta = buildMeta(pageKey, json, superglue, rsp, fetchArgs);
865
+ if (json.action !== "handleStreamResponse") {
866
+ if (placeholderKey && hasPropsAt(path) && hasPlaceholder) {
867
+ const existingId = pages[placeholderKey]?.componentIdentifier;
868
+ const receivedId = json.componentIdentifier;
869
+ if (!!existingId && existingId != receivedId) {
870
+ const message = `You received a page response with a
561
871
  componentIdentifier "${receivedId}" that is different than the
562
872
  componentIdentifier "${existingId}" located at ${placeholderKey}.
563
873
 
@@ -573,29 +883,50 @@ Check that you're rendering a page with a matching
573
883
  componentIdentifier, or consider using redirect_back_with_props_at
574
884
  to the same page.
575
885
  `;
576
- throw new MismatchedComponentError(message);
886
+ throw new MismatchedComponentError(message);
887
+ }
888
+ dispatch(copyPage({ from: placeholderKey, to: pageKey }));
577
889
  }
578
- dispatch(copyPage({ from: placeholderKey, to: pageKey }));
579
890
  }
580
- const meta = buildMeta(pageKey, json, superglue, rsp, fetchArgs);
581
891
  const visitMeta = {
582
892
  ...meta,
583
893
  navigationAction: calculateNavAction(
584
894
  meta,
585
895
  rsp,
896
+ json,
586
897
  isGet,
587
898
  pageKey,
588
899
  currentPageKey,
589
900
  revisit
590
901
  )
591
902
  };
592
- const page = beforeSave(pages[pageKey], json);
903
+ dispatch(
904
+ receiveResponse({
905
+ pageKey,
906
+ response: JSON.parse(JSON.stringify(json))
907
+ })
908
+ );
909
+ const existingPage = createProxy(
910
+ pages[pageKey],
911
+ { current: fragments },
912
+ /* @__PURE__ */ new Set(),
913
+ /* @__PURE__ */ new WeakMap()
914
+ );
915
+ let page = json;
916
+ if (json.action === "savePage" || json.action === "graft") {
917
+ page = JSON.parse(
918
+ JSON.stringify(beforeSave(existingPage, json))
919
+ );
920
+ }
593
921
  return dispatch(saveAndProcessPage(pageKey, page)).then(() => visitMeta);
594
922
  }).catch((e) => handleFetchErr(e, fetchArgs, dispatch));
595
923
  };
596
924
  };
597
- function calculateNavAction(meta, rsp, isGet, pageKey, currentPageKey, revisit) {
925
+ function calculateNavAction(meta, rsp, json, isGet, pageKey, currentPageKey, revisit) {
598
926
  let navigationAction = "push";
927
+ if (json.action === "handleStreamResponse") {
928
+ return "none";
929
+ }
599
930
  if (!rsp.redirected && !isGet) {
600
931
  navigationAction = "replace";
601
932
  }
@@ -624,6 +955,155 @@ function calculatePageKey(rsp, isGet, currentPageKey) {
624
955
  return pageKey;
625
956
  }
626
957
 
958
+ // lib/action_creators/stream.ts
959
+ var streamPrepend = (fragments, data, options = {}) => {
960
+ return (dispatch) => {
961
+ if (options.saveAs) {
962
+ const { saveAs } = options;
963
+ dispatch(
964
+ saveFragment({
965
+ fragmentId: saveAs,
966
+ data
967
+ })
968
+ );
969
+ fragments.forEach((fragmentId) => {
970
+ dispatch(
971
+ prependToFragment({
972
+ fragmentId,
973
+ data: {
974
+ __id: saveAs
975
+ }
976
+ })
977
+ );
978
+ });
979
+ } else {
980
+ fragments.forEach((fragmentId) => {
981
+ dispatch(
982
+ prependToFragment({
983
+ fragmentId,
984
+ data
985
+ })
986
+ );
987
+ });
988
+ }
989
+ };
990
+ };
991
+ var streamAppend = (fragments, data, options = {}) => {
992
+ return (dispatch) => {
993
+ if (options.saveAs) {
994
+ const { saveAs } = options;
995
+ dispatch(
996
+ saveFragment({
997
+ fragmentId: saveAs,
998
+ data
999
+ })
1000
+ );
1001
+ fragments.forEach((fragmentId) => {
1002
+ dispatch(
1003
+ appendToFragment({
1004
+ fragmentId,
1005
+ data: {
1006
+ __id: saveAs
1007
+ }
1008
+ })
1009
+ );
1010
+ });
1011
+ } else {
1012
+ fragments.forEach((fragmentId) => {
1013
+ dispatch(
1014
+ appendToFragment({
1015
+ fragmentId,
1016
+ data
1017
+ })
1018
+ );
1019
+ });
1020
+ }
1021
+ };
1022
+ };
1023
+ var streamSave = (fragment, data) => {
1024
+ return (dispatch) => {
1025
+ dispatch(
1026
+ saveFragment({
1027
+ fragmentId: fragment,
1028
+ data
1029
+ })
1030
+ );
1031
+ };
1032
+ };
1033
+ var handleStreamMessage = (rawMessage) => {
1034
+ return (dispatch) => {
1035
+ const message = JSON.parse(rawMessage);
1036
+ let nextMessage = message;
1037
+ if (message.handler !== "refresh") {
1038
+ message.fragments.reverse().forEach((fragment) => {
1039
+ const { id, path } = fragment;
1040
+ const node = getIn(nextMessage, path);
1041
+ nextMessage = setIn(nextMessage, path, { __id: id });
1042
+ dispatch(
1043
+ saveFragment({
1044
+ fragmentId: id,
1045
+ data: node
1046
+ })
1047
+ );
1048
+ });
1049
+ }
1050
+ if (nextMessage.action === "handleStreamMessage") {
1051
+ if (nextMessage.handler === "append") {
1052
+ dispatch(
1053
+ streamAppend(
1054
+ nextMessage.fragmentIds,
1055
+ nextMessage.data,
1056
+ nextMessage.options
1057
+ )
1058
+ );
1059
+ }
1060
+ if (nextMessage.handler === "prepend") {
1061
+ dispatch(
1062
+ streamPrepend(
1063
+ nextMessage.fragmentIds,
1064
+ nextMessage.data,
1065
+ nextMessage.options
1066
+ )
1067
+ );
1068
+ }
1069
+ if (nextMessage.handler === "save") {
1070
+ dispatch(streamSave(nextMessage.fragmentIds[0], nextMessage.data));
1071
+ }
1072
+ }
1073
+ };
1074
+ };
1075
+ var handleStreamResponse = (response) => {
1076
+ return (dispatch) => {
1077
+ let nextResponse = response;
1078
+ nextResponse.fragments.reverse().forEach((fragment) => {
1079
+ const { id, path } = fragment;
1080
+ const node = getIn(nextResponse, path);
1081
+ nextResponse = setIn(nextResponse, path, { __id: id });
1082
+ dispatch(
1083
+ saveFragment({
1084
+ fragmentId: id,
1085
+ data: node
1086
+ })
1087
+ );
1088
+ });
1089
+ nextResponse.data.forEach((message) => {
1090
+ if (message.handler === "append") {
1091
+ dispatch(
1092
+ streamAppend(message.fragmentIds, message.data, message.options)
1093
+ );
1094
+ }
1095
+ if (message.handler === "prepend") {
1096
+ dispatch(
1097
+ streamPrepend(message.fragmentIds, message.data, message.options)
1098
+ );
1099
+ }
1100
+ if (message.handler === "save") {
1101
+ dispatch(streamSave(message.fragmentIds[0], message.data));
1102
+ }
1103
+ });
1104
+ };
1105
+ };
1106
+
627
1107
  // lib/action_creators/index.ts
628
1108
  function fetchDeferments(pageKey, defers = []) {
629
1109
  pageKey = urlToPageKey(pageKey);
@@ -657,58 +1137,64 @@ function fetchDeferments(pageKey, defers = []) {
657
1137
  return Promise.all(fetches);
658
1138
  };
659
1139
  }
1140
+ function addPlaceholdersToDeferredNodes(existingPage, page) {
1141
+ const { defers = [] } = existingPage;
1142
+ const prevDefers = defers.map(({ path }) => {
1143
+ const node = getIn(existingPage, path);
1144
+ const copy = JSON.stringify(node);
1145
+ return [path, JSON.parse(copy)];
1146
+ });
1147
+ return prevDefers.reduce((memo, [path, node]) => {
1148
+ return setIn(page, path, node);
1149
+ }, page);
1150
+ }
660
1151
  function saveAndProcessPage(pageKey, page) {
661
1152
  return (dispatch, getState) => {
662
1153
  pageKey = urlToPageKey(pageKey);
663
- const { defers = [] } = page;
664
- if ("action" in page) {
665
- const prevPage = getState().pages[pageKey];
666
- dispatch(handleGraft({ pageKey, page }));
667
- const currentPage = getState().pages[pageKey];
668
- currentPage.fragments.forEach((fragment) => {
669
- const { type, path } = fragment;
670
- const currentFragment = getIn(currentPage, path);
671
- const prevFragment = getIn(prevPage, path);
672
- if (!prevFragment) {
673
- dispatch(
674
- updateFragments({
675
- name: type,
676
- pageKey,
677
- value: currentFragment,
678
- path
679
- })
680
- );
681
- } else if (currentFragment !== prevFragment) {
682
- dispatch(
683
- updateFragments({
684
- name: type,
685
- pageKey,
686
- value: currentFragment,
687
- previousValue: prevFragment,
688
- path
689
- })
690
- );
691
- }
692
- });
693
- } else {
694
- dispatch(saveResponse({ pageKey, page }));
695
- const currentPage = getState().pages[pageKey];
696
- currentPage.fragments.forEach((fragment) => {
697
- const { type, path } = fragment;
698
- const currentFragment = getIn(currentPage, path);
1154
+ let nextPage = page;
1155
+ const state = getState();
1156
+ if (page.action === "savePage" && state.pages[pageKey]) {
1157
+ const existingPage = createProxy(
1158
+ state.pages[pageKey],
1159
+ { current: state.fragments },
1160
+ /* @__PURE__ */ new Set(),
1161
+ /* @__PURE__ */ new WeakMap()
1162
+ );
1163
+ nextPage = JSON.parse(
1164
+ JSON.stringify(addPlaceholdersToDeferredNodes(existingPage, nextPage))
1165
+ );
1166
+ }
1167
+ page.fragments.slice().reverse().forEach((fragment) => {
1168
+ const { id, path } = fragment;
1169
+ const node = getIn(nextPage, path);
1170
+ nextPage = setIn(nextPage, path, { __id: id });
1171
+ dispatch(
1172
+ saveFragment({
1173
+ fragmentId: id,
1174
+ data: node
1175
+ })
1176
+ );
1177
+ });
1178
+ if (nextPage.action === "graft") {
1179
+ if (typeof nextPage.fragmentContext === "string") {
699
1180
  dispatch(
700
- updateFragments({
701
- name: type,
702
- pageKey,
703
- value: currentFragment,
704
- path
1181
+ handleFragmentGraft({
1182
+ fragmentId: nextPage.fragmentContext,
1183
+ response: nextPage
705
1184
  })
706
1185
  );
707
- });
1186
+ } else {
1187
+ dispatch(handleGraft({ pageKey, page: nextPage }));
1188
+ }
1189
+ } else if (nextPage.action === "handleStreamResponse") {
1190
+ dispatch(handleStreamResponse(nextPage));
1191
+ return Promise.resolve();
1192
+ } else {
1193
+ dispatch(saveResponse({ pageKey, page: nextPage }));
708
1194
  }
709
1195
  const hasFetch = typeof fetch != "undefined";
710
1196
  if (hasFetch) {
711
- return dispatch(fetchDeferments(pageKey, defers)).then(
1197
+ return dispatch(fetchDeferments(pageKey, nextPage.defers)).then(
712
1198
  () => Promise.resolve()
713
1199
  );
714
1200
  } else {
@@ -724,12 +1210,12 @@ export {
724
1210
  argsForHistory,
725
1211
  getIn,
726
1212
  setIn,
1213
+ lastRequestIds,
727
1214
  ujsHandlers,
728
1215
  GRAFTING_ERROR,
729
1216
  GRAFTING_SUCCESS,
730
1217
  saveResponse,
731
1218
  handleGraft,
732
- updateFragments,
733
1219
  copyPage,
734
1220
  removePage,
735
1221
  beforeFetch,
@@ -738,9 +1224,20 @@ export {
738
1224
  setCSRFToken,
739
1225
  historyChange,
740
1226
  setActivePage,
1227
+ handleFragmentGraft,
1228
+ saveFragment,
1229
+ receiveResponse,
1230
+ appendToFragment,
1231
+ prependToFragment,
1232
+ createProxy,
1233
+ unproxy,
741
1234
  MismatchedComponentError,
742
1235
  remote,
743
1236
  visit,
1237
+ streamPrepend,
1238
+ streamAppend,
1239
+ streamSave,
1240
+ handleStreamMessage,
744
1241
  saveAndProcessPage
745
1242
  };
746
- //# sourceMappingURL=chunk-ENOVWJUC.mjs.map
1243
+ //# sourceMappingURL=chunk-J2XH5QTK.mjs.map