@thoughtbot/superglue 1.0.2 → 2.0.0-alpha.2

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.
@@ -1,3 +1,29 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __commonJS = (cb, mod) => function __require() {
8
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
19
+ // If the importer is in node compatibility mode or this is not an ESM
20
+ // file that has been converted to a CommonJS file using a Babel-
21
+ // compatible transform (i.e. "__esModule" has not been set), then set
22
+ // "default" to the CommonJS "module.exports" for node compatibility.
23
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
24
+ mod
25
+ ));
26
+
1
27
  // lib/utils/url.ts
2
28
  var FAKE_ORIGIN = "https://example.com";
3
29
  function pathQuery(url) {
@@ -179,7 +205,26 @@ var config = {
179
205
  maxPages: 20
180
206
  };
181
207
 
208
+ // lib/utils/limited_set.ts
209
+ var LimitedSet = class extends Set {
210
+ constructor(maxSize) {
211
+ super();
212
+ this.maxSize = maxSize;
213
+ }
214
+ add(value) {
215
+ if (this.size >= this.maxSize) {
216
+ const iterator = this.values();
217
+ const oldestValue = iterator.next().value;
218
+ this.delete(oldestValue);
219
+ }
220
+ super.add(value);
221
+ return this;
222
+ }
223
+ };
224
+
182
225
  // lib/utils/request.ts
226
+ import { v4 as uuidv4 } from "uuid";
227
+ var lastRequestIds = new LimitedSet(20);
183
228
  function isValidResponse(xhr) {
184
229
  return isValidContent(xhr) && !downloadingFile(xhr);
185
230
  }
@@ -235,6 +280,9 @@ function argsForFetch(getState, pathQuery2, {
235
280
  nextHeaders["x-requested-with"] = "XMLHttpRequest";
236
281
  nextHeaders["accept"] = "application/json";
237
282
  nextHeaders["x-superglue-request"] = "true";
283
+ const requestId = uuidv4();
284
+ lastRequestIds.add(requestId);
285
+ nextHeaders["X-Superglue-Request-Id"] = requestId;
238
286
  if (method != "GET" && method != "HEAD") {
239
287
  nextHeaders["content-type"] = "application/json";
240
288
  }
@@ -428,7 +476,6 @@ var handleGraft = createAction(
428
476
  var superglueError = createAction(
429
477
  "@@superglue/ERROR"
430
478
  );
431
- var updateFragments = createAction("@@superglue/UPDATE_FRAGMENTS");
432
479
  var copyPage = createAction(
433
480
  "@@superglue/COPY_PAGE"
434
481
  );
@@ -443,6 +490,65 @@ var beforeRemote = createAction("@@superglue/BEFORE_REMOTE");
443
490
  var setCSRFToken = createAction("@@superglue/SET_CSRF_TOKEN");
444
491
  var historyChange = createAction("@@superglue/HISTORY_CHANGE");
445
492
  var setActivePage = createAction("@@superglue/SET_ACTIVE_PAGE");
493
+ var handleFragmentGraft = createAction(
494
+ "@@superglue/HANDLE_FRAGMENT_GRAFT",
495
+ ({
496
+ fragmentId,
497
+ response
498
+ }) => {
499
+ return {
500
+ payload: {
501
+ response,
502
+ fragmentId
503
+ }
504
+ };
505
+ }
506
+ );
507
+ var saveFragment = createAction(
508
+ "@@superglue/SAVE_FRAGMENT",
509
+ ({ fragmentId, data }) => {
510
+ return {
511
+ payload: {
512
+ fragmentId,
513
+ data
514
+ }
515
+ };
516
+ }
517
+ );
518
+ var receiveResponse = createAction(
519
+ "@@superglue/RECEIVE_RESPONSE",
520
+ ({ pageKey, response }) => {
521
+ pageKey = urlToPageKey(pageKey);
522
+ return {
523
+ payload: {
524
+ pageKey,
525
+ response
526
+ }
527
+ };
528
+ }
529
+ );
530
+ var appendToFragment = createAction(
531
+ "@@superglue/APPEND_TO_FRAGMENT",
532
+ ({ data, fragmentId }) => {
533
+ return {
534
+ payload: {
535
+ data,
536
+ fragmentId
537
+ }
538
+ };
539
+ }
540
+ );
541
+ var prependToFragment = createAction(
542
+ "@@superglue/PREPEND_TO_FRAGMENT",
543
+ ({ data, fragmentId }) => {
544
+ return {
545
+ payload: {
546
+ data,
547
+ fragmentId
548
+ }
549
+ };
550
+ }
551
+ );
446
552
 
447
553
  // lib/action_creators/requests.ts
448
554
  function handleFetchErr(err, fetchArgs, dispatch) {
@@ -452,15 +558,18 @@ function handleFetchErr(err, fetchArgs, dispatch) {
452
558
  function buildMeta(pageKey, page, state, rsp, fetchArgs) {
453
559
  const { assets: prevAssets } = state;
454
560
  const { assets: nextAssets } = page;
455
- return {
561
+ const meta = {
456
562
  pageKey,
457
563
  page,
458
564
  redirected: rsp.redirected,
459
565
  rsp,
460
566
  fetchArgs,
461
- componentIdentifier: page.componentIdentifier,
462
567
  needsRefresh: needsRefresh(prevAssets, nextAssets)
463
568
  };
569
+ if (page.action !== "handleStreamResponse") {
570
+ meta.componentIdentifier = page.componentIdentifier;
571
+ }
572
+ return meta;
464
573
  }
465
574
  var MismatchedComponentError = class extends Error {
466
575
  constructor(message) {
@@ -468,10 +577,11 @@ var MismatchedComponentError = class extends Error {
468
577
  this.name = "MismatchedComponentError";
469
578
  }
470
579
  };
580
+ var defaultBeforeSave = (prevPage, receivedPage) => receivedPage;
471
581
  var remote = (path, {
472
582
  pageKey: targetPageKey,
473
583
  force = false,
474
- beforeSave = (prevPage, receivedPage) => receivedPage,
584
+ beforeSave = defaultBeforeSave,
475
585
  ...rest
476
586
  } = {}) => {
477
587
  targetPageKey = targetPageKey && urlToPageKey(targetPageKey);
@@ -490,10 +600,11 @@ var remote = (path, {
490
600
  pageKey = targetPageKey;
491
601
  }
492
602
  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
603
+ if (json.action !== "handleStreamResponse") {
604
+ const existingId = pages[pageKey]?.componentIdentifier;
605
+ const receivedId = json.componentIdentifier;
606
+ if (!!existingId && existingId != receivedId && !force) {
607
+ const message = `You cannot replace or update an existing page
497
608
  located at pages["${currentPageKey}"] that has a componentIdentifier
498
609
  of "${existingId}" with the contents of a page response that has a
499
610
  componentIdentifier of "${receivedId}".
@@ -509,8 +620,10 @@ compatible with the page component associated with "${existingId}".
509
620
  Consider using data-sg-visit, the visit function, or redirect_back to
510
621
  the same page. Or if you're sure you want to proceed, use force: true.
511
622
  `;
512
- throw new MismatchedComponentError(message);
623
+ throw new MismatchedComponentError(message);
624
+ }
513
625
  }
626
+ dispatch(receiveResponse({ pageKey, response: json }));
514
627
  const page = beforeSave(pages[pageKey], json);
515
628
  return dispatch(saveAndProcessPage(pageKey, page)).then(() => meta);
516
629
  }).catch((e) => handleFetchErr(e, fetchArgs, dispatch));
@@ -553,11 +666,13 @@ var visit = (path, {
553
666
  const { superglue, pages = {} } = getState();
554
667
  const isGet = fetchArgs[1].method === "GET";
555
668
  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
669
+ const meta = buildMeta(pageKey, json, superglue, rsp, fetchArgs);
670
+ if (json.action !== "handleStreamResponse") {
671
+ if (placeholderKey && hasPropsAt(path) && hasPlaceholder) {
672
+ const existingId = pages[placeholderKey]?.componentIdentifier;
673
+ const receivedId = json.componentIdentifier;
674
+ if (!!existingId && existingId != receivedId) {
675
+ const message = `You received a page response with a
561
676
  componentIdentifier "${receivedId}" that is different than the
562
677
  componentIdentifier "${existingId}" located at ${placeholderKey}.
563
678
 
@@ -573,29 +688,34 @@ Check that you're rendering a page with a matching
573
688
  componentIdentifier, or consider using redirect_back_with_props_at
574
689
  to the same page.
575
690
  `;
576
- throw new MismatchedComponentError(message);
691
+ throw new MismatchedComponentError(message);
692
+ }
693
+ dispatch(copyPage({ from: placeholderKey, to: pageKey }));
577
694
  }
578
- dispatch(copyPage({ from: placeholderKey, to: pageKey }));
579
695
  }
580
- const meta = buildMeta(pageKey, json, superglue, rsp, fetchArgs);
581
696
  const visitMeta = {
582
697
  ...meta,
583
698
  navigationAction: calculateNavAction(
584
699
  meta,
585
700
  rsp,
701
+ json,
586
702
  isGet,
587
703
  pageKey,
588
704
  currentPageKey,
589
705
  revisit
590
706
  )
591
707
  };
708
+ dispatch(receiveResponse({ pageKey, response: json }));
592
709
  const page = beforeSave(pages[pageKey], json);
593
710
  return dispatch(saveAndProcessPage(pageKey, page)).then(() => visitMeta);
594
711
  }).catch((e) => handleFetchErr(e, fetchArgs, dispatch));
595
712
  };
596
713
  };
597
- function calculateNavAction(meta, rsp, isGet, pageKey, currentPageKey, revisit) {
714
+ function calculateNavAction(meta, rsp, json, isGet, pageKey, currentPageKey, revisit) {
598
715
  let navigationAction = "push";
716
+ if (json.action === "handleStreamResponse") {
717
+ return "none";
718
+ }
599
719
  if (!rsp.redirected && !isGet) {
600
720
  navigationAction = "replace";
601
721
  }
@@ -624,6 +744,359 @@ function calculatePageKey(rsp, isGet, currentPageKey) {
624
744
  return pageKey;
625
745
  }
626
746
 
747
+ // lib/action_creators/stream.ts
748
+ var streamPrepend = (fragments, data, options = {}) => {
749
+ return (dispatch) => {
750
+ if (options.saveAs) {
751
+ const { saveAs } = options;
752
+ dispatch(
753
+ saveFragment({
754
+ fragmentId: saveAs,
755
+ data
756
+ })
757
+ );
758
+ fragments.forEach((fragmentId) => {
759
+ dispatch(
760
+ prependToFragment({
761
+ fragmentId,
762
+ data: {
763
+ __id: saveAs
764
+ }
765
+ })
766
+ );
767
+ });
768
+ } else {
769
+ fragments.forEach((fragmentId) => {
770
+ dispatch(
771
+ prependToFragment({
772
+ fragmentId,
773
+ data
774
+ })
775
+ );
776
+ });
777
+ }
778
+ };
779
+ };
780
+ var streamAppend = (fragments, data, options = {}) => {
781
+ return (dispatch) => {
782
+ if (options.saveAs) {
783
+ const { saveAs } = options;
784
+ dispatch(
785
+ saveFragment({
786
+ fragmentId: saveAs,
787
+ data
788
+ })
789
+ );
790
+ fragments.forEach((fragmentId) => {
791
+ dispatch(
792
+ appendToFragment({
793
+ fragmentId,
794
+ data: {
795
+ __id: saveAs
796
+ }
797
+ })
798
+ );
799
+ });
800
+ } else {
801
+ fragments.forEach((fragmentId) => {
802
+ dispatch(
803
+ appendToFragment({
804
+ fragmentId,
805
+ data
806
+ })
807
+ );
808
+ });
809
+ }
810
+ };
811
+ };
812
+ var streamSave = (fragment, data) => {
813
+ return (dispatch) => {
814
+ dispatch(
815
+ saveFragment({
816
+ fragmentId: fragment,
817
+ data
818
+ })
819
+ );
820
+ };
821
+ };
822
+ var handleStreamMessage = (rawMessage) => {
823
+ return (dispatch) => {
824
+ const message = JSON.parse(rawMessage);
825
+ let nextMessage = message;
826
+ if (message.handler !== "refresh") {
827
+ message.fragments.reverse().forEach((fragment) => {
828
+ const { id, path } = fragment;
829
+ const node = getIn(nextMessage, path);
830
+ nextMessage = setIn(nextMessage, path, { __id: id });
831
+ dispatch(
832
+ saveFragment({
833
+ fragmentId: id,
834
+ data: node
835
+ })
836
+ );
837
+ });
838
+ }
839
+ if (nextMessage.action === "handleStreamMessage") {
840
+ if (nextMessage.handler === "append") {
841
+ dispatch(
842
+ streamAppend(
843
+ nextMessage.fragmentIds,
844
+ nextMessage.data,
845
+ nextMessage.options
846
+ )
847
+ );
848
+ }
849
+ if (nextMessage.handler === "prepend") {
850
+ dispatch(
851
+ streamPrepend(
852
+ nextMessage.fragmentIds,
853
+ nextMessage.data,
854
+ nextMessage.options
855
+ )
856
+ );
857
+ }
858
+ if (nextMessage.handler === "save") {
859
+ dispatch(streamSave(nextMessage.fragmentIds[0], nextMessage.data));
860
+ }
861
+ }
862
+ };
863
+ };
864
+ var handleStreamResponse = (response) => {
865
+ return (dispatch) => {
866
+ let nextResponse = response;
867
+ nextResponse.fragments.reverse().forEach((fragment) => {
868
+ const { id, path } = fragment;
869
+ const node = getIn(nextResponse, path);
870
+ nextResponse = setIn(nextResponse, path, { __id: id });
871
+ dispatch(
872
+ saveFragment({
873
+ fragmentId: id,
874
+ data: node
875
+ })
876
+ );
877
+ });
878
+ nextResponse.data.forEach((message) => {
879
+ if (message.handler === "append") {
880
+ dispatch(
881
+ streamAppend(message.fragmentIds, message.data, message.options)
882
+ );
883
+ }
884
+ if (message.handler === "prepend") {
885
+ dispatch(
886
+ streamPrepend(message.fragmentIds, message.data, message.options)
887
+ );
888
+ }
889
+ if (message.handler === "save") {
890
+ dispatch(streamSave(message.fragmentIds[0], message.data));
891
+ }
892
+ });
893
+ };
894
+ };
895
+
896
+ // lib/utils/proxy.ts
897
+ var ORIGINAL_TARGET = Symbol("@@originalTarget");
898
+ var ARRAY_GETTER_METHODS = /* @__PURE__ */ new Set([
899
+ Symbol.iterator,
900
+ "at",
901
+ "concat",
902
+ "entries",
903
+ "every",
904
+ "filter",
905
+ "find",
906
+ "findIndex",
907
+ "flat",
908
+ "flatMap",
909
+ "forEach",
910
+ "includes",
911
+ "indexOf",
912
+ "join",
913
+ "keys",
914
+ "lastIndexOf",
915
+ "map",
916
+ "reduce",
917
+ "reduceRight",
918
+ "slice",
919
+ "some",
920
+ "toString",
921
+ "values"
922
+ ]);
923
+ var ARRAY_SETTER_METHODS = /* @__PURE__ */ new Set([
924
+ "copyWithin",
925
+ "fill",
926
+ "pop",
927
+ "push",
928
+ "reverse",
929
+ "shift",
930
+ "sort",
931
+ "splice",
932
+ "unshift"
933
+ ]);
934
+ function isArraySetter(prop) {
935
+ return ARRAY_SETTER_METHODS.has(prop);
936
+ }
937
+ function isArrayGetter(prop) {
938
+ return ARRAY_GETTER_METHODS.has(prop);
939
+ }
940
+ function convertToInt(prop) {
941
+ if (typeof prop === "symbol") return null;
942
+ const num = Number(prop);
943
+ return Number.isInteger(num) ? num : null;
944
+ }
945
+ function isFragmentReference(value) {
946
+ return !!value && typeof value === "object" && "__id" in value && typeof value.__id === "string";
947
+ }
948
+ function createArrayProxy(arrayData, fragments, dependencies, proxyCache) {
949
+ if (proxyCache && proxyCache.has(arrayData)) {
950
+ return proxyCache.get(arrayData);
951
+ }
952
+ const proxy = new Proxy(arrayData, {
953
+ get(target, prop) {
954
+ if (prop === ORIGINAL_TARGET) {
955
+ return target;
956
+ }
957
+ if (isArrayGetter(prop)) {
958
+ const method = target[prop];
959
+ if (typeof method === "function") {
960
+ return function(...args) {
961
+ return Reflect.apply(method, proxy, args);
962
+ };
963
+ }
964
+ return method;
965
+ }
966
+ if (isArraySetter(prop)) {
967
+ throw new Error(
968
+ `Cannot mutate proxy array. Use Redux actions to update state.`
969
+ );
970
+ }
971
+ const index = convertToInt(prop);
972
+ if (index !== null && index >= 0 && index < target.length) {
973
+ const item = target[index];
974
+ if (isFragmentReference(item)) {
975
+ dependencies.add(item.__id);
976
+ const fragmentData = fragments.current[item.__id];
977
+ if (!fragmentData) {
978
+ throw new Error(`Fragment with id "${item.__id}" not found`);
979
+ }
980
+ return createProxy(fragmentData, fragments, dependencies, proxyCache);
981
+ }
982
+ if (typeof item === "object" && item !== null) {
983
+ if ("$$typeof" in item) {
984
+ return item;
985
+ } else {
986
+ return createProxy(
987
+ item,
988
+ fragments,
989
+ dependencies,
990
+ proxyCache
991
+ );
992
+ }
993
+ }
994
+ return item;
995
+ }
996
+ return Reflect.get(target, prop);
997
+ },
998
+ has(target, prop) {
999
+ if (prop === ORIGINAL_TARGET) {
1000
+ return true;
1001
+ }
1002
+ return Reflect.has(target, prop);
1003
+ },
1004
+ set() {
1005
+ throw new Error(
1006
+ "Cannot mutate proxy array. Use Redux actions to update state."
1007
+ );
1008
+ },
1009
+ deleteProperty() {
1010
+ throw new Error(
1011
+ "Cannot delete properties on proxy array. Use Redux actions to update state."
1012
+ );
1013
+ },
1014
+ defineProperty() {
1015
+ throw new Error(
1016
+ "Cannot define properties on proxy array. Use Redux actions to update state."
1017
+ );
1018
+ }
1019
+ });
1020
+ if (proxyCache) {
1021
+ proxyCache.set(arrayData, proxy);
1022
+ }
1023
+ return proxy;
1024
+ }
1025
+ function createObjectProxy(objectData, fragments, dependencies, proxyCache) {
1026
+ if (proxyCache && proxyCache.has(objectData)) {
1027
+ return proxyCache.get(objectData);
1028
+ }
1029
+ const proxy = new Proxy(objectData, {
1030
+ get(target, prop) {
1031
+ if (prop === ORIGINAL_TARGET) {
1032
+ return target;
1033
+ }
1034
+ const value = target[prop];
1035
+ if (isFragmentReference(value)) {
1036
+ dependencies.add(value.__id);
1037
+ const fragmentData = fragments.current[value.__id];
1038
+ if (!fragmentData) {
1039
+ throw new Error(`Fragment with id "${value.__id}" not found`);
1040
+ }
1041
+ return createProxy(fragmentData, fragments, dependencies, proxyCache);
1042
+ }
1043
+ if (typeof value === "object" && value !== null) {
1044
+ if ("$$typeof" in value) {
1045
+ return value;
1046
+ } else if (Array.isArray(value)) {
1047
+ return createArrayProxy(value, fragments, dependencies, proxyCache);
1048
+ } else {
1049
+ return createObjectProxy(value, fragments, dependencies, proxyCache);
1050
+ }
1051
+ }
1052
+ return value;
1053
+ },
1054
+ has(target, prop) {
1055
+ if (prop === ORIGINAL_TARGET) {
1056
+ return true;
1057
+ }
1058
+ return Reflect.has(target, prop);
1059
+ },
1060
+ set() {
1061
+ throw new Error(
1062
+ "Cannot mutate proxy object. Use Redux actions to update state."
1063
+ );
1064
+ },
1065
+ deleteProperty() {
1066
+ throw new Error(
1067
+ "Cannot delete properties on proxy object. Use Redux actions to update state."
1068
+ );
1069
+ },
1070
+ defineProperty() {
1071
+ throw new Error(
1072
+ "Cannot define properties on proxy object. Use Redux actions to update state."
1073
+ );
1074
+ }
1075
+ });
1076
+ if (proxyCache) {
1077
+ proxyCache.set(objectData, proxy);
1078
+ }
1079
+ return proxy;
1080
+ }
1081
+ function createProxy(content, fragments, dependencies, proxyCache) {
1082
+ if (!content || typeof content !== "object") {
1083
+ return content;
1084
+ }
1085
+ if ("$$typeof" in content) {
1086
+ return content;
1087
+ }
1088
+ if (Array.isArray(content)) {
1089
+ return createArrayProxy(content, fragments, dependencies, proxyCache);
1090
+ }
1091
+ return createObjectProxy(content, fragments, dependencies, proxyCache);
1092
+ }
1093
+ function unproxy(proxy) {
1094
+ if (proxy && typeof proxy === "object" && ORIGINAL_TARGET in proxy) {
1095
+ return proxy[ORIGINAL_TARGET];
1096
+ }
1097
+ return proxy;
1098
+ }
1099
+
627
1100
  // lib/action_creators/index.ts
628
1101
  function fetchDeferments(pageKey, defers = []) {
629
1102
  pageKey = urlToPageKey(pageKey);
@@ -657,58 +1130,64 @@ function fetchDeferments(pageKey, defers = []) {
657
1130
  return Promise.all(fetches);
658
1131
  };
659
1132
  }
1133
+ function addPlaceholdersToDeferredNodes(existingPage, page) {
1134
+ const { defers = [] } = existingPage;
1135
+ const prevDefers = defers.map(({ path }) => {
1136
+ const node = getIn(existingPage, path);
1137
+ const copy = JSON.stringify(node);
1138
+ return [path, JSON.parse(copy)];
1139
+ });
1140
+ return prevDefers.reduce((memo, [path, node]) => {
1141
+ return setIn(page, path, node);
1142
+ }, page);
1143
+ }
660
1144
  function saveAndProcessPage(pageKey, page) {
661
1145
  return (dispatch, getState) => {
662
1146
  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);
1147
+ let nextPage = page;
1148
+ const state = getState();
1149
+ if (page.action === "savePage" && state.pages[pageKey]) {
1150
+ const existingPage = createProxy(
1151
+ state.pages[pageKey],
1152
+ { current: state.fragments },
1153
+ /* @__PURE__ */ new Set(),
1154
+ /* @__PURE__ */ new WeakMap()
1155
+ );
1156
+ nextPage = JSON.parse(
1157
+ JSON.stringify(addPlaceholdersToDeferredNodes(existingPage, nextPage))
1158
+ );
1159
+ }
1160
+ page.fragments.reverse().forEach((fragment) => {
1161
+ const { id, path } = fragment;
1162
+ const node = getIn(nextPage, path);
1163
+ nextPage = setIn(page, path, { __id: id });
1164
+ dispatch(
1165
+ saveFragment({
1166
+ fragmentId: id,
1167
+ data: node
1168
+ })
1169
+ );
1170
+ });
1171
+ if (nextPage.action === "graft") {
1172
+ if (typeof nextPage.fragmentContext === "string") {
699
1173
  dispatch(
700
- updateFragments({
701
- name: type,
702
- pageKey,
703
- value: currentFragment,
704
- path
1174
+ handleFragmentGraft({
1175
+ fragmentId: nextPage.fragmentContext,
1176
+ response: nextPage
705
1177
  })
706
1178
  );
707
- });
1179
+ } else {
1180
+ dispatch(handleGraft({ pageKey, page: nextPage }));
1181
+ }
1182
+ } else if (nextPage.action === "handleStreamResponse") {
1183
+ dispatch(handleStreamResponse(nextPage));
1184
+ return Promise.resolve();
1185
+ } else {
1186
+ dispatch(saveResponse({ pageKey, page: nextPage }));
708
1187
  }
709
1188
  const hasFetch = typeof fetch != "undefined";
710
1189
  if (hasFetch) {
711
- return dispatch(fetchDeferments(pageKey, defers)).then(
1190
+ return dispatch(fetchDeferments(pageKey, nextPage.defers)).then(
712
1191
  () => Promise.resolve()
713
1192
  );
714
1193
  } else {
@@ -718,18 +1197,20 @@ function saveAndProcessPage(pageKey, page) {
718
1197
  }
719
1198
 
720
1199
  export {
1200
+ __commonJS,
1201
+ __toESM,
721
1202
  config,
722
1203
  urlToPageKey,
723
1204
  parsePageKey,
724
1205
  argsForHistory,
725
1206
  getIn,
726
1207
  setIn,
1208
+ lastRequestIds,
727
1209
  ujsHandlers,
728
1210
  GRAFTING_ERROR,
729
1211
  GRAFTING_SUCCESS,
730
1212
  saveResponse,
731
1213
  handleGraft,
732
- updateFragments,
733
1214
  copyPage,
734
1215
  removePage,
735
1216
  beforeFetch,
@@ -738,9 +1219,20 @@ export {
738
1219
  setCSRFToken,
739
1220
  historyChange,
740
1221
  setActivePage,
1222
+ handleFragmentGraft,
1223
+ saveFragment,
1224
+ receiveResponse,
1225
+ appendToFragment,
1226
+ prependToFragment,
741
1227
  MismatchedComponentError,
742
1228
  remote,
743
1229
  visit,
1230
+ streamPrepend,
1231
+ streamAppend,
1232
+ streamSave,
1233
+ handleStreamMessage,
1234
+ createProxy,
1235
+ unproxy,
744
1236
  saveAndProcessPage
745
1237
  };
746
- //# sourceMappingURL=chunk-7OMO5P27.mjs.map
1238
+ //# sourceMappingURL=chunk-EU2SLL5L.mjs.map