@thoughtbot/superglue 1.0.2 → 2.0.0-alpha.1
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/.tool-versions +1 -1
- package/dist/action_creators.d.mts +1 -1
- package/dist/action_creators.mjs +1 -1
- package/dist/{chunk-7OMO5P27.mjs → chunk-YS477OKK.mjs} +312 -64
- package/dist/chunk-YS477OKK.mjs.map +1 -0
- package/dist/cjs/action_creators.cjs +263 -62
- package/dist/cjs/action_creators.cjs.map +1 -1
- package/dist/cjs/superglue.cjs +6205 -91
- package/dist/cjs/superglue.cjs.map +1 -1
- package/dist/{index-BYr1PoYr.d.mts → index-MyfFLe4E.d.mts} +55 -16
- package/dist/superglue.d.mts +55 -14
- package/dist/superglue.mjs +5947 -34
- package/dist/superglue.mjs.map +1 -1
- package/package.json +11 -4
- package/thoughtbot-superglue-2.0.0-alpha.1.tgz +0 -0
- package/dist/chunk-7OMO5P27.mjs.map +0 -1
|
@@ -100,6 +100,9 @@ function getIn(node, path) {
|
|
|
100
100
|
return void 0;
|
|
101
101
|
}
|
|
102
102
|
}
|
|
103
|
+
function clone(node) {
|
|
104
|
+
return Array.isArray(node) ? [].slice.call(node) : { ...node };
|
|
105
|
+
}
|
|
103
106
|
function getKey(node, key) {
|
|
104
107
|
if (Array.isArray(node) && Number.isNaN(Number(key))) {
|
|
105
108
|
const key_parts = Array.from(key.split("="));
|
|
@@ -148,6 +151,34 @@ function normalizeKeyPath(path) {
|
|
|
148
151
|
return path;
|
|
149
152
|
}
|
|
150
153
|
}
|
|
154
|
+
function setIn(object, path, value) {
|
|
155
|
+
const keypath = normalizeKeyPath(path);
|
|
156
|
+
const results = { 0: object };
|
|
157
|
+
const parents = { 0: object };
|
|
158
|
+
let i;
|
|
159
|
+
for (i = 0; i < keypath.length; i++) {
|
|
160
|
+
const parent = parents[i];
|
|
161
|
+
if (!(typeof parent === "object" && parent !== null)) {
|
|
162
|
+
throw new KeyPathError(
|
|
163
|
+
`Expected to traverse an Array or Obj, got ${JSON.stringify(parent)}`
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
const child = atKey(parent, keypath[i]);
|
|
167
|
+
parents[i + 1] = child;
|
|
168
|
+
}
|
|
169
|
+
results[keypath.length] = value;
|
|
170
|
+
for (i = keypath.length - 1; i >= 0; i--) {
|
|
171
|
+
const target = clone(parents[i]);
|
|
172
|
+
results[i] = target;
|
|
173
|
+
const key = getKey(results[i], keypath[i]);
|
|
174
|
+
if (Array.isArray(target)) {
|
|
175
|
+
target[key] = results[i + 1];
|
|
176
|
+
} else {
|
|
177
|
+
target[key] = results[i + 1];
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
return results[0];
|
|
181
|
+
}
|
|
151
182
|
|
|
152
183
|
// lib/config.ts
|
|
153
184
|
var config = {
|
|
@@ -155,7 +186,26 @@ var config = {
|
|
|
155
186
|
maxPages: 20
|
|
156
187
|
};
|
|
157
188
|
|
|
189
|
+
// lib/utils/limited_set.ts
|
|
190
|
+
var LimitedSet = class extends Set {
|
|
191
|
+
constructor(maxSize) {
|
|
192
|
+
super();
|
|
193
|
+
this.maxSize = maxSize;
|
|
194
|
+
}
|
|
195
|
+
add(value) {
|
|
196
|
+
if (this.size >= this.maxSize) {
|
|
197
|
+
const iterator = this.values();
|
|
198
|
+
const oldestValue = iterator.next().value;
|
|
199
|
+
this.delete(oldestValue);
|
|
200
|
+
}
|
|
201
|
+
super.add(value);
|
|
202
|
+
return this;
|
|
203
|
+
}
|
|
204
|
+
};
|
|
205
|
+
|
|
158
206
|
// lib/utils/request.ts
|
|
207
|
+
var import_uuid = require("uuid");
|
|
208
|
+
var lastRequestIds = new LimitedSet(20);
|
|
159
209
|
function isValidResponse(xhr) {
|
|
160
210
|
return isValidContent(xhr) && !downloadingFile(xhr);
|
|
161
211
|
}
|
|
@@ -211,6 +261,9 @@ function argsForFetch(getState, pathQuery2, {
|
|
|
211
261
|
nextHeaders["x-requested-with"] = "XMLHttpRequest";
|
|
212
262
|
nextHeaders["accept"] = "application/json";
|
|
213
263
|
nextHeaders["x-superglue-request"] = "true";
|
|
264
|
+
const requestId = (0, import_uuid.v4)();
|
|
265
|
+
lastRequestIds.add(requestId);
|
|
266
|
+
nextHeaders["X-Superglue-Request-Id"] = requestId;
|
|
214
267
|
if (method != "GET" && method != "HEAD") {
|
|
215
268
|
nextHeaders["content-type"] = "application/json";
|
|
216
269
|
}
|
|
@@ -302,7 +355,6 @@ var handleGraft = (0, import_toolkit.createAction)(
|
|
|
302
355
|
var superglueError = (0, import_toolkit.createAction)(
|
|
303
356
|
"@@superglue/ERROR"
|
|
304
357
|
);
|
|
305
|
-
var updateFragments = (0, import_toolkit.createAction)("@@superglue/UPDATE_FRAGMENTS");
|
|
306
358
|
var copyPage = (0, import_toolkit.createAction)(
|
|
307
359
|
"@@superglue/COPY_PAGE"
|
|
308
360
|
);
|
|
@@ -317,6 +369,53 @@ var beforeRemote = (0, import_toolkit.createAction)("@@superglue/BEFORE_REMOTE")
|
|
|
317
369
|
var setCSRFToken = (0, import_toolkit.createAction)("@@superglue/SET_CSRF_TOKEN");
|
|
318
370
|
var historyChange = (0, import_toolkit.createAction)("@@superglue/HISTORY_CHANGE");
|
|
319
371
|
var setActivePage = (0, import_toolkit.createAction)("@@superglue/SET_ACTIVE_PAGE");
|
|
372
|
+
var handleFragmentGraft = (0, import_toolkit.createAction)(
|
|
373
|
+
"@@superglue/HANDLE_FRAGMENT_GRAFT",
|
|
374
|
+
({
|
|
375
|
+
fragmentId,
|
|
376
|
+
response
|
|
377
|
+
}) => {
|
|
378
|
+
return {
|
|
379
|
+
payload: {
|
|
380
|
+
response,
|
|
381
|
+
fragmentId
|
|
382
|
+
}
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
);
|
|
386
|
+
var saveFragment = (0, import_toolkit.createAction)(
|
|
387
|
+
"@@superglue/SAVE_FRAGMENT",
|
|
388
|
+
({ fragmentId, data }) => {
|
|
389
|
+
return {
|
|
390
|
+
payload: {
|
|
391
|
+
fragmentId,
|
|
392
|
+
data
|
|
393
|
+
}
|
|
394
|
+
};
|
|
395
|
+
}
|
|
396
|
+
);
|
|
397
|
+
var appendToFragment = (0, import_toolkit.createAction)(
|
|
398
|
+
"@@superglue/APPEND_TO_FRAGMENT",
|
|
399
|
+
({ data, fragmentId }) => {
|
|
400
|
+
return {
|
|
401
|
+
payload: {
|
|
402
|
+
data,
|
|
403
|
+
fragmentId
|
|
404
|
+
}
|
|
405
|
+
};
|
|
406
|
+
}
|
|
407
|
+
);
|
|
408
|
+
var prependToFragment = (0, import_toolkit.createAction)(
|
|
409
|
+
"@@superglue/PREPEND_TO_FRAGMENT",
|
|
410
|
+
({ data, fragmentId }) => {
|
|
411
|
+
return {
|
|
412
|
+
payload: {
|
|
413
|
+
data,
|
|
414
|
+
fragmentId
|
|
415
|
+
}
|
|
416
|
+
};
|
|
417
|
+
}
|
|
418
|
+
);
|
|
320
419
|
|
|
321
420
|
// lib/action_creators/requests.ts
|
|
322
421
|
function handleFetchErr(err, fetchArgs, dispatch) {
|
|
@@ -326,15 +425,18 @@ function handleFetchErr(err, fetchArgs, dispatch) {
|
|
|
326
425
|
function buildMeta(pageKey, page, state, rsp, fetchArgs) {
|
|
327
426
|
const { assets: prevAssets } = state;
|
|
328
427
|
const { assets: nextAssets } = page;
|
|
329
|
-
|
|
428
|
+
const meta = {
|
|
330
429
|
pageKey,
|
|
331
430
|
page,
|
|
332
431
|
redirected: rsp.redirected,
|
|
333
432
|
rsp,
|
|
334
433
|
fetchArgs,
|
|
335
|
-
componentIdentifier: page.componentIdentifier,
|
|
336
434
|
needsRefresh: needsRefresh(prevAssets, nextAssets)
|
|
337
435
|
};
|
|
436
|
+
if (page.action !== "handleStreamResponse") {
|
|
437
|
+
meta.componentIdentifier = page.componentIdentifier;
|
|
438
|
+
}
|
|
439
|
+
return meta;
|
|
338
440
|
}
|
|
339
441
|
var MismatchedComponentError = class extends Error {
|
|
340
442
|
constructor(message) {
|
|
@@ -342,10 +444,11 @@ var MismatchedComponentError = class extends Error {
|
|
|
342
444
|
this.name = "MismatchedComponentError";
|
|
343
445
|
}
|
|
344
446
|
};
|
|
447
|
+
var defaultBeforeSave = (prevPage, receivedPage) => receivedPage;
|
|
345
448
|
var remote = (path, {
|
|
346
449
|
pageKey: targetPageKey,
|
|
347
450
|
force = false,
|
|
348
|
-
beforeSave =
|
|
451
|
+
beforeSave = defaultBeforeSave,
|
|
349
452
|
...rest
|
|
350
453
|
} = {}) => {
|
|
351
454
|
targetPageKey = targetPageKey && urlToPageKey(targetPageKey);
|
|
@@ -364,10 +467,11 @@ var remote = (path, {
|
|
|
364
467
|
pageKey = targetPageKey;
|
|
365
468
|
}
|
|
366
469
|
const meta = buildMeta(pageKey, json, superglue, rsp, fetchArgs);
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
470
|
+
if (json.action !== "handleStreamResponse") {
|
|
471
|
+
const existingId = pages[pageKey]?.componentIdentifier;
|
|
472
|
+
const receivedId = json.componentIdentifier;
|
|
473
|
+
if (!!existingId && existingId != receivedId && !force) {
|
|
474
|
+
const message = `You cannot replace or update an existing page
|
|
371
475
|
located at pages["${currentPageKey}"] that has a componentIdentifier
|
|
372
476
|
of "${existingId}" with the contents of a page response that has a
|
|
373
477
|
componentIdentifier of "${receivedId}".
|
|
@@ -383,7 +487,8 @@ compatible with the page component associated with "${existingId}".
|
|
|
383
487
|
Consider using data-sg-visit, the visit function, or redirect_back to
|
|
384
488
|
the same page. Or if you're sure you want to proceed, use force: true.
|
|
385
489
|
`;
|
|
386
|
-
|
|
490
|
+
throw new MismatchedComponentError(message);
|
|
491
|
+
}
|
|
387
492
|
}
|
|
388
493
|
const page = beforeSave(pages[pageKey], json);
|
|
389
494
|
return dispatch(saveAndProcessPage(pageKey, page)).then(() => meta);
|
|
@@ -427,11 +532,13 @@ var visit = (path, {
|
|
|
427
532
|
const { superglue, pages = {} } = getState();
|
|
428
533
|
const isGet = fetchArgs[1].method === "GET";
|
|
429
534
|
const pageKey = calculatePageKey(rsp, isGet, currentPageKey);
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
const
|
|
535
|
+
const meta = buildMeta(pageKey, json, superglue, rsp, fetchArgs);
|
|
536
|
+
if (json.action !== "handleStreamResponse") {
|
|
537
|
+
if (placeholderKey && hasPropsAt(path) && hasPlaceholder) {
|
|
538
|
+
const existingId = pages[placeholderKey]?.componentIdentifier;
|
|
539
|
+
const receivedId = json.componentIdentifier;
|
|
540
|
+
if (!!existingId && existingId != receivedId) {
|
|
541
|
+
const message = `You received a page response with a
|
|
435
542
|
componentIdentifier "${receivedId}" that is different than the
|
|
436
543
|
componentIdentifier "${existingId}" located at ${placeholderKey}.
|
|
437
544
|
|
|
@@ -447,16 +554,17 @@ Check that you're rendering a page with a matching
|
|
|
447
554
|
componentIdentifier, or consider using redirect_back_with_props_at
|
|
448
555
|
to the same page.
|
|
449
556
|
`;
|
|
450
|
-
|
|
557
|
+
throw new MismatchedComponentError(message);
|
|
558
|
+
}
|
|
559
|
+
dispatch(copyPage({ from: placeholderKey, to: pageKey }));
|
|
451
560
|
}
|
|
452
|
-
dispatch(copyPage({ from: placeholderKey, to: pageKey }));
|
|
453
561
|
}
|
|
454
|
-
const meta = buildMeta(pageKey, json, superglue, rsp, fetchArgs);
|
|
455
562
|
const visitMeta = {
|
|
456
563
|
...meta,
|
|
457
564
|
navigationAction: calculateNavAction(
|
|
458
565
|
meta,
|
|
459
566
|
rsp,
|
|
567
|
+
json,
|
|
460
568
|
isGet,
|
|
461
569
|
pageKey,
|
|
462
570
|
currentPageKey,
|
|
@@ -468,8 +576,11 @@ to the same page.
|
|
|
468
576
|
}).catch((e) => handleFetchErr(e, fetchArgs, dispatch));
|
|
469
577
|
};
|
|
470
578
|
};
|
|
471
|
-
function calculateNavAction(meta, rsp, isGet, pageKey, currentPageKey, revisit) {
|
|
579
|
+
function calculateNavAction(meta, rsp, json, isGet, pageKey, currentPageKey, revisit) {
|
|
472
580
|
let navigationAction = "push";
|
|
581
|
+
if (json.action === "handleStreamResponse") {
|
|
582
|
+
return "none";
|
|
583
|
+
}
|
|
473
584
|
if (!rsp.redirected && !isGet) {
|
|
474
585
|
navigationAction = "replace";
|
|
475
586
|
}
|
|
@@ -498,6 +609,113 @@ function calculatePageKey(rsp, isGet, currentPageKey) {
|
|
|
498
609
|
return pageKey;
|
|
499
610
|
}
|
|
500
611
|
|
|
612
|
+
// lib/action_creators/stream.ts
|
|
613
|
+
var streamPrepend = (fragments, data, options = {}) => {
|
|
614
|
+
return (dispatch) => {
|
|
615
|
+
if (options.saveAs) {
|
|
616
|
+
const { saveAs } = options;
|
|
617
|
+
dispatch(
|
|
618
|
+
saveFragment({
|
|
619
|
+
fragmentId: saveAs,
|
|
620
|
+
data
|
|
621
|
+
})
|
|
622
|
+
);
|
|
623
|
+
fragments.forEach((fragmentId) => {
|
|
624
|
+
dispatch(
|
|
625
|
+
prependToFragment({
|
|
626
|
+
fragmentId,
|
|
627
|
+
data: {
|
|
628
|
+
__id: saveAs
|
|
629
|
+
}
|
|
630
|
+
})
|
|
631
|
+
);
|
|
632
|
+
});
|
|
633
|
+
} else {
|
|
634
|
+
fragments.forEach((fragmentId) => {
|
|
635
|
+
dispatch(
|
|
636
|
+
prependToFragment({
|
|
637
|
+
fragmentId,
|
|
638
|
+
data
|
|
639
|
+
})
|
|
640
|
+
);
|
|
641
|
+
});
|
|
642
|
+
}
|
|
643
|
+
};
|
|
644
|
+
};
|
|
645
|
+
var streamAppend = (fragments, data, options = {}) => {
|
|
646
|
+
return (dispatch) => {
|
|
647
|
+
if (options.saveAs) {
|
|
648
|
+
const { saveAs } = options;
|
|
649
|
+
dispatch(
|
|
650
|
+
saveFragment({
|
|
651
|
+
fragmentId: saveAs,
|
|
652
|
+
data
|
|
653
|
+
})
|
|
654
|
+
);
|
|
655
|
+
fragments.forEach((fragmentId) => {
|
|
656
|
+
dispatch(
|
|
657
|
+
appendToFragment({
|
|
658
|
+
fragmentId,
|
|
659
|
+
data: {
|
|
660
|
+
__id: saveAs
|
|
661
|
+
}
|
|
662
|
+
})
|
|
663
|
+
);
|
|
664
|
+
});
|
|
665
|
+
} else {
|
|
666
|
+
fragments.forEach((fragmentId) => {
|
|
667
|
+
dispatch(
|
|
668
|
+
appendToFragment({
|
|
669
|
+
fragmentId,
|
|
670
|
+
data
|
|
671
|
+
})
|
|
672
|
+
);
|
|
673
|
+
});
|
|
674
|
+
}
|
|
675
|
+
};
|
|
676
|
+
};
|
|
677
|
+
var streamSave = (fragment, data) => {
|
|
678
|
+
return (dispatch) => {
|
|
679
|
+
dispatch(
|
|
680
|
+
saveFragment({
|
|
681
|
+
fragmentId: fragment,
|
|
682
|
+
data
|
|
683
|
+
})
|
|
684
|
+
);
|
|
685
|
+
};
|
|
686
|
+
};
|
|
687
|
+
var handleStreamResponse = (response) => {
|
|
688
|
+
return (dispatch) => {
|
|
689
|
+
let nextResponse = response;
|
|
690
|
+
nextResponse.fragments.reverse().forEach((fragment) => {
|
|
691
|
+
const { id, path } = fragment;
|
|
692
|
+
const node = getIn(nextResponse, path);
|
|
693
|
+
nextResponse = setIn(nextResponse, path, { __id: id });
|
|
694
|
+
dispatch(
|
|
695
|
+
saveFragment({
|
|
696
|
+
fragmentId: id,
|
|
697
|
+
data: node
|
|
698
|
+
})
|
|
699
|
+
);
|
|
700
|
+
});
|
|
701
|
+
nextResponse.data.forEach((message) => {
|
|
702
|
+
if (message.handler === "append") {
|
|
703
|
+
dispatch(
|
|
704
|
+
streamAppend(message.fragmentIds, message.data, message.options)
|
|
705
|
+
);
|
|
706
|
+
}
|
|
707
|
+
if (message.handler === "prepend") {
|
|
708
|
+
dispatch(
|
|
709
|
+
streamPrepend(message.fragmentIds, message.data, message.options)
|
|
710
|
+
);
|
|
711
|
+
}
|
|
712
|
+
if (message.handler === "save") {
|
|
713
|
+
dispatch(streamSave(message.fragmentIds[0], message.data));
|
|
714
|
+
}
|
|
715
|
+
});
|
|
716
|
+
};
|
|
717
|
+
};
|
|
718
|
+
|
|
501
719
|
// lib/action_creators/index.ts
|
|
502
720
|
function fetchDeferments(pageKey, defers = []) {
|
|
503
721
|
pageKey = urlToPageKey(pageKey);
|
|
@@ -532,57 +750,40 @@ function fetchDeferments(pageKey, defers = []) {
|
|
|
532
750
|
};
|
|
533
751
|
}
|
|
534
752
|
function saveAndProcessPage(pageKey, page) {
|
|
535
|
-
return (dispatch
|
|
753
|
+
return (dispatch) => {
|
|
536
754
|
pageKey = urlToPageKey(pageKey);
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
const
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
value: currentFragment,
|
|
552
|
-
path
|
|
553
|
-
})
|
|
554
|
-
);
|
|
555
|
-
} else if (currentFragment !== prevFragment) {
|
|
556
|
-
dispatch(
|
|
557
|
-
updateFragments({
|
|
558
|
-
name: type,
|
|
559
|
-
pageKey,
|
|
560
|
-
value: currentFragment,
|
|
561
|
-
previousValue: prevFragment,
|
|
562
|
-
path
|
|
563
|
-
})
|
|
564
|
-
);
|
|
565
|
-
}
|
|
566
|
-
});
|
|
567
|
-
} else {
|
|
568
|
-
dispatch(saveResponse({ pageKey, page }));
|
|
569
|
-
const currentPage = getState().pages[pageKey];
|
|
570
|
-
currentPage.fragments.forEach((fragment) => {
|
|
571
|
-
const { type, path } = fragment;
|
|
572
|
-
const currentFragment = getIn(currentPage, path);
|
|
755
|
+
let nextPage = page;
|
|
756
|
+
page.fragments.reverse().forEach((fragment) => {
|
|
757
|
+
const { id, path } = fragment;
|
|
758
|
+
const node = getIn(nextPage, path);
|
|
759
|
+
nextPage = setIn(page, path, { __id: id });
|
|
760
|
+
dispatch(
|
|
761
|
+
saveFragment({
|
|
762
|
+
fragmentId: id,
|
|
763
|
+
data: node
|
|
764
|
+
})
|
|
765
|
+
);
|
|
766
|
+
});
|
|
767
|
+
if (nextPage.action === "graft") {
|
|
768
|
+
if (typeof nextPage.fragmentContext === "string") {
|
|
573
769
|
dispatch(
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
value: currentFragment,
|
|
578
|
-
path
|
|
770
|
+
handleFragmentGraft({
|
|
771
|
+
fragmentId: nextPage.fragmentContext,
|
|
772
|
+
response: nextPage
|
|
579
773
|
})
|
|
580
774
|
);
|
|
581
|
-
}
|
|
775
|
+
} else {
|
|
776
|
+
dispatch(handleGraft({ pageKey, page: nextPage }));
|
|
777
|
+
}
|
|
778
|
+
} else if (nextPage.action === "handleStreamResponse") {
|
|
779
|
+
dispatch(handleStreamResponse(nextPage));
|
|
780
|
+
return Promise.resolve();
|
|
781
|
+
} else {
|
|
782
|
+
dispatch(saveResponse({ pageKey, page: nextPage }));
|
|
582
783
|
}
|
|
583
784
|
const hasFetch = typeof fetch != "undefined";
|
|
584
785
|
if (hasFetch) {
|
|
585
|
-
return dispatch(fetchDeferments(pageKey, defers)).then(
|
|
786
|
+
return dispatch(fetchDeferments(pageKey, nextPage.defers)).then(
|
|
586
787
|
() => Promise.resolve()
|
|
587
788
|
);
|
|
588
789
|
} else {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../lib/action_creators/index.ts","../../lib/utils/url.ts","../../lib/utils/immutability.ts","../../lib/config.ts","../../lib/utils/request.ts","../../lib/utils/window.ts","../../lib/actions.ts","../../lib/action_creators/requests.ts"],"sourcesContent":["import { urlToPageKey, getIn, propsAtParam } from '../utils'\nimport {\n saveResponse,\n GRAFTING_ERROR,\n GRAFTING_SUCCESS,\n updateFragments,\n handleGraft,\n} from '../actions'\nimport { remote } from './requests'\nimport {\n VisitResponse,\n SaveAndProcessPageThunk,\n DefermentThunk,\n GraftResponse,\n Defer,\n JSONMappable,\n} from '../types'\nexport * from './requests'\n\nfunction fetchDeferments(\n pageKey: string,\n defers: Defer[] = []\n): DefermentThunk {\n pageKey = urlToPageKey(pageKey)\n return (dispatch) => {\n const fetches = defers\n .filter(({ type }) => type === 'auto')\n .map(function ({\n url,\n successAction = GRAFTING_SUCCESS,\n failAction = GRAFTING_ERROR,\n }) {\n // props_at will always be present in a graft response\n // That's why this is marked `as string`\n const keyPath = propsAtParam(url) as string\n\n return dispatch(remote(url, { pageKey }))\n .then(() => {\n dispatch({\n type: successAction,\n payload: {\n pageKey,\n keyPath,\n },\n })\n })\n .catch((err) => {\n dispatch({\n type: failAction,\n payload: {\n url,\n err,\n pageKey,\n keyPath,\n },\n })\n })\n })\n\n return Promise.all(fetches)\n }\n}\n\n/**\n * Save and process a rendered view from PropsTemplate. This is the primitive\n * function that `visit` and `remote` calls when it receives a page.\n *\n * If you render a page outside the normal request response cycle, e.g,\n * websocket, you can use this function to save the payload.\n */\nexport function saveAndProcessPage(\n pageKey: string,\n page: VisitResponse | GraftResponse\n): SaveAndProcessPageThunk {\n return (dispatch, getState) => {\n pageKey = urlToPageKey(pageKey)\n\n const { defers = [] } = page\n\n if ('action' in page) {\n const prevPage = getState().pages[pageKey]\n dispatch(handleGraft({ pageKey, page }))\n const currentPage = getState().pages[pageKey]\n\n currentPage.fragments.forEach((fragment) => {\n const { type, path } = fragment\n // A fragment only works on a block in props_template. So using getIn\n // will always return a JSONMappable\n const currentFragment = getIn(currentPage, path) as JSONMappable\n const prevFragment = getIn(prevPage, path) as JSONMappable\n if (!prevFragment) {\n dispatch(\n updateFragments({\n name: type,\n pageKey: pageKey,\n value: currentFragment,\n path,\n })\n )\n } else if (currentFragment !== prevFragment) {\n dispatch(\n updateFragments({\n name: type,\n pageKey: pageKey,\n value: currentFragment,\n previousValue: prevFragment,\n path,\n })\n )\n }\n })\n } else {\n dispatch(saveResponse({ pageKey, page }))\n const currentPage = getState().pages[pageKey]\n\n currentPage.fragments.forEach((fragment) => {\n const { type, path } = fragment\n const currentFragment = getIn(currentPage, path) as JSONMappable\n\n dispatch(\n updateFragments({\n name: type,\n pageKey: pageKey,\n value: currentFragment,\n path,\n })\n )\n })\n }\n\n const hasFetch = typeof fetch != 'undefined'\n if (hasFetch) {\n return dispatch(fetchDeferments(pageKey, defers)).then(() =>\n Promise.resolve()\n )\n } else {\n return Promise.resolve()\n }\n }\n}\n","import { PageKey } from '../types'\n\nconst FAKE_ORIGIN = 'https://example.com'\n\nexport function pathQuery(url: string): string {\n const { pathname, search: query } = new URL(url, FAKE_ORIGIN)\n\n return pathname + query\n}\n\nexport function pathQueryHash(url: string): string {\n const { pathname, hash, search: query } = new URL(url, FAKE_ORIGIN)\n\n return pathname + query + hash\n}\n\nexport function hasPropsAt(url: string): boolean {\n const { searchParams } = new URL(url, FAKE_ORIGIN)\n\n return searchParams.has('props_at')\n}\n\nexport function propsAtParam(url: string): string | null {\n const { searchParams } = new URL(url, FAKE_ORIGIN)\n\n return searchParams.get('props_at')\n}\n\nexport function withFormatJson(url: string): string {\n const parsed = new URL(url, FAKE_ORIGIN)\n parsed.searchParams.set('format', 'json')\n\n return parsed.href.replace(parsed.origin, '')\n}\n\nexport function removePropsAt(url: string): string {\n const parsed = new URL(url, FAKE_ORIGIN)\n parsed.searchParams.delete('props_at')\n\n return parsed.href.replace(parsed.origin, '')\n}\n\n/**\n * Converts a url to a PageKey.\n *\n * @param url\n * @returns\n */\nexport function urlToPageKey(url: string): PageKey {\n const parsed = new URL(url, FAKE_ORIGIN)\n parsed.searchParams.delete('props_at')\n parsed.searchParams.delete('format')\n\n return pathQuery(parsed.toString())\n}\n\nexport function withoutHash(url: string): string {\n const parsed = new URL(url, FAKE_ORIGIN)\n parsed.hash = ''\n\n return parsed.href.replace(parsed.origin, '')\n}\n\nexport function formatForXHR(url: string): string {\n const formats = [withoutHash, withFormatJson]\n\n return formats.reduce((memo, f) => f(memo), url)\n}\n\nexport function parsePageKey(pageKey: PageKey) {\n const { pathname, searchParams } = new URL(pageKey, FAKE_ORIGIN)\n\n const search = Object.fromEntries(searchParams)\n\n return {\n pathname,\n search,\n }\n}\n","// These were taken from Scour.js\n// Then, modified to respect the id=0 keypath\n\nimport { JSONMappable, JSONValue, Keypath } from '../types'\n\nconst canLookAhead = /^[\\da-zA-Z\\-_]+=[\\da-zA-Z\\-_]+$/\n\nclass KeyPathError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'KeyPathError'\n }\n}\n\n/**\n * Retrieves data from a JSON object using a {@link Keypath}\n *\n * @param node\n * @param path\n * @returns\n */\nfunction getIn(node: JSONMappable, path: Keypath): JSONValue {\n const keyPath = normalizeKeyPath(path)\n let result: JSONValue = node\n let i: number\n\n for (i = 0; i < keyPath.length; i++) {\n const key = keyPath[i]\n\n if (typeof result === 'object' && result !== null) {\n if (!Array.isArray(result) && canLookAhead.test(key)) {\n throw new KeyPathError(\n `Expected to find an Array when using the key: ${key}`\n )\n }\n\n result = atKey(result, key)\n } else {\n throw new KeyPathError(\n `Expected to traverse an Array or Obj, got ${JSON.stringify(result)}`\n )\n }\n }\n\n if (i === keyPath.length) {\n return result\n } else {\n return undefined\n }\n}\n\nfunction clone(node: JSONMappable): JSONMappable {\n return Array.isArray(node) ? [].slice.call(node) : { ...node }\n}\n\nfunction getKey(node: JSONMappable, key: string): string | number | never {\n if (Array.isArray(node) && Number.isNaN(Number(key))) {\n const key_parts = Array.from(key.split('='))\n const attr = key_parts[0]\n const id = key_parts[1]\n\n if (!id || !attr) {\n return key\n }\n\n let i: number\n let child: JSONValue\n\n for (i = 0; i < node.length; i++) {\n child = node[i]\n if (\n typeof child === 'object' &&\n !Array.isArray(child) &&\n child !== null\n ) {\n const val = child[attr]\n if (val && val.toString() === id) {\n break\n }\n } else {\n throw new KeyPathError(`Could not look ahead ${key} at ${child}`)\n }\n }\n\n if (i === node.length) {\n throw new KeyPathError(`Could not find ${key} while looking ahead`)\n }\n\n return i\n } else {\n return key\n }\n}\n\nfunction atKey(node: JSONMappable, key: string) {\n const actualKey = getKey(node, key)\n\n if (Array.isArray(node)) {\n return node[actualKey as number]\n } else {\n return node[actualKey]\n }\n}\n\nfunction normalizeKeyPath(path: string): string[] {\n if (typeof path === 'string') {\n path = path.replace(/ /g, '')\n if (path === '') {\n return []\n }\n\n return path.split('.')\n } else {\n return path\n }\n}\n/**\n * Sets data into a JSON object using a {@link Keypath}\n *\n * @param object\n * @param path\n * @param value\n * @returns\n */\nfunction setIn<T extends JSONMappable>(\n object: T,\n path: string,\n value: JSONValue\n): T | never {\n const keypath = normalizeKeyPath(path)\n\n const results: {\n 0: T\n [key: number]: JSONValue\n } = { 0: object }\n\n const parents: {\n 0: T\n [key: number]: JSONValue\n } = { 0: object }\n\n let i: number\n\n for (i = 0; i < keypath.length; i++) {\n const parent = parents[i]\n\n if (!(typeof parent === 'object' && parent !== null)) {\n throw new KeyPathError(\n `Expected to traverse an Array or Obj, got ${JSON.stringify(parent)}`\n )\n }\n\n const child = atKey(parent, keypath[i])\n parents[i + 1] = child\n }\n\n results[keypath.length] = value\n\n for (i = keypath.length - 1; i >= 0; i--) {\n // Parents will always have a JSONValue at\n // keypath.length so this loop skips that one element\n // Every other element in parents is a JSONMappable\n const target = clone(parents[i] as JSONMappable)\n results[i] = target\n const key = getKey(results[i] as JSONMappable, keypath[i])\n if (Array.isArray(target)) {\n target[key as number] = results[i + 1]\n } else {\n target[key] = results[i + 1]\n }\n }\n\n return results[0]\n}\n\nexport { getIn, setIn, KeyPathError }\n","export const config = {\n baseUrl: '',\n maxPages: 20,\n}\n","import { formatForXHR } from './url'\nimport { config } from '../config'\nimport { BasicRequestInit, ParsedResponse, RootState } from '../types'\n\nexport function isValidResponse(xhr: Response): boolean {\n return isValidContent(xhr) && !downloadingFile(xhr)\n}\n\nexport function isValidContent(rsp: Response): boolean {\n const contentType = rsp.headers.get('content-type')\n const jsContent = /^(?:application\\/json)(?:;|$)/\n\n return !!(contentType && contentType.match(jsContent))\n}\n\nfunction downloadingFile(xhr: Response): boolean {\n const disposition = xhr.headers.get('content-disposition')\n\n return !!(disposition && disposition.match(/^attachment/) !== null)\n}\n\nclass SuperglueResponseError extends Error {\n response: Response\n\n constructor(message: string) {\n super(message)\n this.name = 'SuperglueResponseError'\n }\n}\n\nexport function validateResponse(args: ParsedResponse): ParsedResponse {\n const { rsp } = args\n if (isValidResponse(rsp)) {\n return args\n } else {\n const error = new SuperglueResponseError('Invalid Superglue Response')\n error.response = rsp\n throw error\n }\n}\n\nexport function handleServerErrors(args: ParsedResponse): ParsedResponse {\n const { rsp } = args\n if (!rsp.ok && rsp.status !== 422) {\n if (rsp.status === 406) {\n console.error(\n \"Superglue encountered a 406 Not Acceptable response. This can happen if you used respond_to and didn't specify format.json in the block. Try adding it to your respond_to. For example:\\n\\n\" +\n 'respond_to do |format|\\n' +\n ' format.html\\n' +\n ' format.json\\n' +\n ' format.csv\\n' +\n 'end'\n )\n }\n const error = new SuperglueResponseError(rsp.statusText)\n error.response = rsp\n throw error\n }\n return args\n}\n\nexport function argsForFetch(\n getState: () => RootState,\n pathQuery: string,\n {\n method = 'GET',\n headers = {},\n body = '',\n signal,\n ...rest\n }: BasicRequestInit = {}\n): [string, BasicRequestInit] {\n method = method.toUpperCase()\n const currentState = getState().superglue\n\n const nextHeaders = { ...headers }\n nextHeaders['x-requested-with'] = 'XMLHttpRequest'\n nextHeaders['accept'] = 'application/json'\n nextHeaders['x-superglue-request'] = 'true'\n\n if (method != 'GET' && method != 'HEAD') {\n nextHeaders['content-type'] = 'application/json'\n }\n\n if (body instanceof FormData) {\n delete nextHeaders['content-type']\n }\n\n if (currentState.csrfToken) {\n nextHeaders['x-csrf-token'] = currentState.csrfToken\n }\n\n const fetchPath = new URL(formatForXHR(pathQuery), config.baseUrl)\n\n const credentials = 'same-origin'\n\n if (!(method == 'GET' || method == 'HEAD')) {\n nextHeaders['x-http-method-override'] = method\n method = 'POST'\n }\n\n const options: BasicRequestInit = {\n method,\n headers: nextHeaders,\n body,\n credentials,\n signal,\n }\n\n if (currentState.currentPageKey) {\n const referrer = new URL(currentState.currentPageKey, config.baseUrl)\n\n options.referrer = referrer.toString()\n }\n\n if (method == 'GET' || method == 'HEAD') {\n if (options.body instanceof FormData) {\n const allData = new URLSearchParams(\n options.body as unknown as Record<string, string>\n )\n\n // Form data should override anything in the URL params First we\n // delete every key. Then append the new keys accounting for\n // duplicate keys that represent structural arrays.\n allData.forEach((value, key) => fetchPath.searchParams.delete(key))\n allData.forEach((value, key) => fetchPath.searchParams.append(key, value))\n }\n\n delete options.body\n }\n\n return [fetchPath.toString(), { ...options, ...rest }]\n}\n\nexport function extractJSON(rsp: Response): PromiseLike<ParsedResponse> {\n return rsp\n .json()\n .then((json) => {\n return { rsp, json }\n })\n .catch((e) => {\n e.response = rsp\n throw e\n })\n}\n\nexport function parseResponse(prm: Response): PromiseLike<ParsedResponse> {\n return Promise.resolve(prm)\n .then(extractJSON)\n .then(handleServerErrors)\n .then(validateResponse)\n}\n","export function needsRefresh(\n prevAssets: string[],\n newAssets: string[]\n): boolean {\n if (prevAssets && newAssets) {\n const hasNewAssets = !newAssets.every((asset) => prevAssets.includes(asset))\n return hasNewAssets\n } else {\n return false\n }\n}\n","import { createAction } from '@reduxjs/toolkit'\nimport {\n FetchArgs,\n PageKey,\n GraftResponse,\n VisitResponse,\n JSONMappable,\n Keypath,\n} from './types'\nimport { urlToPageKey } from './utils'\n\nexport const GRAFTING_ERROR = '@@superglue/GRAFTING_ERROR'\nexport const GRAFTING_SUCCESS = '@@superglue/GRAFTING_SUCCESS'\n\nexport const saveResponse = createAction(\n '@@superglue/SAVE_RESPONSE',\n ({ pageKey, page }: { pageKey: string; page: VisitResponse }) => {\n pageKey = urlToPageKey(pageKey)\n\n return {\n payload: {\n pageKey,\n page,\n },\n }\n }\n)\n\nexport const handleGraft = createAction(\n '@@superglue/HANDLE_GRAFT',\n ({ pageKey, page }: { pageKey: string; page: GraftResponse }) => {\n pageKey = urlToPageKey(pageKey)\n\n return {\n payload: {\n page,\n pageKey,\n },\n }\n }\n)\n\nexport const superglueError = createAction<{ message: string }>(\n '@@superglue/ERROR'\n)\n\n/**\n * A redux action called whenever a fragment is received from `visit` or updated\n * using `remote`. Its a useful action to use for cross cutting concerns like a\n * shared header or a shopping cart. For example:\n *\n * ```\n * import { updateFragments } from '@thoughtbot/superglue'\n *\n * export const exampleSlice = createSlice({\n * name: 'Example',\n * initialState: {},\n * extraReducers: (builder) => {\n * builder.addCase(updateFragments, (state, action) => {\n * // Update the slice using the latest and greatest.\n * return action.value\n * ```\n */\nexport const updateFragments = createAction<{\n name: string\n path: Keypath\n pageKey: PageKey\n value: JSONMappable\n previousValue?: JSONMappable\n}>('@@superglue/UPDATE_FRAGMENTS')\n\n/**\n * A redux action you can dispatch to copy a page from one pageKey to another. Its\n * a very useful way to create optimistic updates with a URL change. For example:\n *\n * ```\n * import { copyPage, remote } from '@thoughtbot/superglue'\n *\n * dispatch(copyPage({ from: originalKey, to: targetKey}))\n *\n * ... make edits to target page and finally\n *\n * navigateTo(targetKey)\n * ```\n */\nexport const copyPage = createAction<{ from: PageKey; to: PageKey }>(\n '@@superglue/COPY_PAGE'\n)\n\n/**\n * A redux action you can dispatch to remove a page from your store.\n *\n * ```\n * import { removePage } from '@thoughtbot/superglue'\n *\n * dispatch(removePage({ pageKey: '/delete_me_please\"}))\n * ```\n */\nexport const removePage = createAction<{ pageKey: PageKey }>(\n '@@superglue/REMOVE_PAGE'\n)\n\n/**\n * A redux action called before a `fetch` takes place. It will fire in `remote`\n * and `visit`. You can hook into this event in your redux slices like this:\n *\n * ```\n * import { beforeFetch } from '@thoughtbot/superglue'\n *\n * export const exampleSlice = createSlice({\n * name: 'Example',\n * initialState: {},\n * extraReducers: (builder) => {\n * builder.addCase(beforeFetch, (state, action) => {\n * ```\n */\nexport const beforeFetch = createAction<{ fetchArgs: FetchArgs }>(\n '@@superglue/BEFORE_FETCH'\n)\n\n/**\n * A redux action called before a `visit` takes place. You can hook into this event\n * in your redux slices like this:\n *\n * ```\n * import { beforeVisit } from '@thoughtbot/superglue'\n *\n * export const exampleSlice = createSlice({\n * name: 'Example',\n * initialState: {},\n * extraReducers: (builder) => {\n * builder.addCase(beforeVisit, (state, action) => {\n * ```\n */\nexport const beforeVisit = createAction<{\n currentPageKey: PageKey\n fetchArgs: FetchArgs\n}>('@@superglue/BEFORE_VISIT')\n\n/**\n * A redux action called before `remote` takes place. You can hook into this event\n * in your redux slices like this:\n *\n * ```\n * import { beforeRemote } from '@thoughtbot/superglue'\n *\n * export const exampleSlice = createSlice({\n * name: 'Example',\n * initialState: {},\n * extraReducers: (builder) => {\n * builder.addCase(beforeRemote, (state, action) => {\n * ```\n */\nexport const beforeRemote = createAction<{\n currentPageKey: PageKey\n fetchArgs: FetchArgs\n}>('@@superglue/BEFORE_REMOTE')\n\nexport const setCSRFToken = createAction<{\n csrfToken: string | undefined\n}>('@@superglue/SET_CSRF_TOKEN')\n\nexport const historyChange = createAction<{\n pageKey: PageKey\n}>('@@superglue/HISTORY_CHANGE')\n\nexport const setActivePage = createAction<{\n pageKey: PageKey\n}>('@@superglue/SET_ACTIVE_PAGE')\n","import {\n argsForFetch,\n parseResponse,\n needsRefresh,\n urlToPageKey,\n hasPropsAt,\n propsAtParam,\n removePropsAt,\n} from '../utils'\nimport {\n beforeFetch,\n beforeVisit,\n beforeRemote,\n copyPage,\n superglueError,\n} from '../actions'\nimport { saveAndProcessPage } from './index'\nimport {\n FetchArgs,\n VisitResponse,\n PageResponse,\n Page,\n SuperglueState,\n Meta,\n Dispatch,\n RemoteCreator,\n VisitCreator,\n NavigationAction,\n VisitMeta,\n} from '../types'\n\nfunction handleFetchErr(\n err: Error,\n fetchArgs: FetchArgs,\n dispatch: Dispatch\n): never {\n dispatch(superglueError({ message: err.message }))\n throw err\n}\n\nfunction buildMeta(\n pageKey: string,\n page: VisitResponse,\n state: SuperglueState,\n rsp: Response,\n fetchArgs: FetchArgs\n): Meta {\n const { assets: prevAssets } = state\n const { assets: nextAssets } = page\n\n return {\n pageKey,\n page,\n redirected: rsp.redirected,\n rsp,\n fetchArgs,\n componentIdentifier: page.componentIdentifier,\n needsRefresh: needsRefresh(prevAssets, nextAssets),\n }\n}\n\nexport class MismatchedComponentError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'MismatchedComponentError'\n }\n}\n\nexport const remote: RemoteCreator = (\n path,\n {\n pageKey: targetPageKey,\n force = false,\n beforeSave = (prevPage: Page, receivedPage: PageResponse) => receivedPage,\n ...rest\n } = {}\n) => {\n targetPageKey = targetPageKey && urlToPageKey(targetPageKey)\n\n return (dispatch, getState) => {\n const fetchArgs = argsForFetch(getState, path, rest)\n const currentPageKey = getState().superglue.currentPageKey\n\n dispatch(beforeRemote({ currentPageKey, fetchArgs }))\n dispatch(beforeFetch({ fetchArgs }))\n\n return fetch(...fetchArgs)\n .then(parseResponse)\n .then(({ rsp, json }) => {\n const { superglue, pages = {} } = getState()\n\n let pageKey\n if (targetPageKey === undefined) {\n const isGet = fetchArgs[1].method === 'GET'\n pageKey = calculatePageKey(rsp, isGet, currentPageKey)\n } else {\n pageKey = targetPageKey\n }\n\n const meta = buildMeta(pageKey, json, superglue, rsp, fetchArgs)\n\n const existingId = pages[pageKey]?.componentIdentifier\n const receivedId = json.componentIdentifier\n if (!!existingId && existingId != receivedId && !force) {\n const message = `You cannot replace or update an existing page\nlocated at pages[\"${currentPageKey}\"] that has a componentIdentifier\nof \"${existingId}\" with the contents of a page response that has a\ncomponentIdentifier of \"${receivedId}\".\n\nThis can happen if you're using data-sg-remote or remote but your\nresponse redirected to a page with a different componentIdentifier\nthan the target page. \n\nThis limitation exists because the resulting page shape from grafting\n\"${receivedId}\"'s \"${propsAtParam(path)}\" into \"${existingId}\" may not be\ncompatible with the page component associated with \"${existingId}\".\n\nConsider using data-sg-visit, the visit function, or redirect_back to\nthe same page. Or if you're sure you want to proceed, use force: true.\n `\n throw new MismatchedComponentError(message)\n }\n\n const page = beforeSave(pages[pageKey], json)\n return dispatch(saveAndProcessPage(pageKey, page)).then(() => meta)\n })\n .catch((e) => handleFetchErr(e, fetchArgs, dispatch))\n }\n}\n\nlet lastVisitController = {\n /* eslint-disable-next-line @typescript-eslint/no-unused-vars */\n abort: (_reason: string) => {\n // noop\n },\n}\n\nexport const visit: VisitCreator = (\n path,\n {\n placeholderKey,\n beforeSave = (prevPage: Page, receivedPage: PageResponse) => receivedPage,\n revisit = false,\n ...rest\n } = {}\n) => {\n return (dispatch, getState) => {\n const currentPageKey = getState().superglue.currentPageKey\n placeholderKey =\n (placeholderKey && urlToPageKey(placeholderKey)) || currentPageKey\n const hasPlaceholder = placeholderKey in getState().pages\n\n if (hasPropsAt(path) && !hasPlaceholder) {\n console.warn(\n `Could not find placeholder with key ${placeholderKey} in state. The props_at param will be ignored`\n )\n path = removePropsAt(path)\n }\n\n const controller = new AbortController()\n const { signal } = controller\n const fetchArgs = argsForFetch(getState, path, {\n ...rest,\n signal,\n })\n\n dispatch(beforeVisit({ currentPageKey, fetchArgs }))\n dispatch(beforeFetch({ fetchArgs }))\n\n lastVisitController.abort(\n 'Aborting the previous `visit`. There can be one visit at a time. Use `remote` if there is a need for async requests.'\n )\n lastVisitController = controller\n\n return fetch(...fetchArgs)\n .then(parseResponse)\n .then(({ rsp, json }) => {\n const { superglue, pages = {} } = getState()\n const isGet = fetchArgs[1].method === 'GET'\n const pageKey = calculatePageKey(rsp, isGet, currentPageKey)\n if (placeholderKey && hasPropsAt(path) && hasPlaceholder) {\n const existingId = pages[placeholderKey]?.componentIdentifier\n const receivedId = json.componentIdentifier\n if (!!existingId && existingId != receivedId) {\n const message = `You received a page response with a\ncomponentIdentifier \"${receivedId}\" that is different than the\ncomponentIdentifier \"${existingId}\" located at ${placeholderKey}.\n\nThis can happen if you're using data-sg-visit or visit with a\nprops_at param, but the response redirected to a page with a\ndifferent componentIdentifier than the target page. \n\nThis limitation exists because the resulting page shape from grafting\n\"${receivedId}\"'s \"${propsAtParam(path)}\" into \"${existingId}\" may not be\ncompatible with the page component associated with \"${existingId}\".\n\nCheck that you're rendering a page with a matching\ncomponentIdentifier, or consider using redirect_back_with_props_at\nto the same page.\n `\n throw new MismatchedComponentError(message)\n }\n dispatch(copyPage({ from: placeholderKey, to: pageKey }))\n }\n\n const meta = buildMeta(pageKey, json, superglue, rsp, fetchArgs)\n\n const visitMeta: VisitMeta = {\n ...meta,\n navigationAction: calculateNavAction(\n meta,\n rsp,\n isGet,\n pageKey,\n currentPageKey,\n revisit\n ),\n }\n\n const page = beforeSave(pages[pageKey], json)\n return dispatch(saveAndProcessPage(pageKey, page)).then(() => visitMeta)\n })\n .catch((e) => handleFetchErr(e, fetchArgs, dispatch))\n }\n}\n\nfunction calculateNavAction(\n meta: Meta,\n rsp: Response,\n isGet: boolean,\n pageKey: string,\n currentPageKey: string,\n revisit: boolean\n) {\n let navigationAction: NavigationAction = 'push'\n if (!rsp.redirected && !isGet) {\n navigationAction = 'replace'\n }\n const isSamePage = pageKey == currentPageKey\n if (isSamePage) {\n navigationAction = 'none'\n }\n if (revisit && isGet) {\n if (rsp.redirected) {\n navigationAction = 'replace'\n } else {\n navigationAction = 'none'\n }\n }\n\n return navigationAction\n}\n\nfunction calculatePageKey(\n rsp: Response,\n isGet: boolean,\n currentPageKey: string\n) {\n let pageKey = urlToPageKey(rsp.url)\n if (!isGet && !rsp.redirected) {\n pageKey = currentPageKey\n }\n\n const contentLocation = rsp.headers.get('content-location')\n if (contentLocation) {\n pageKey = urlToPageKey(contentLocation)\n }\n return pageKey\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACEA,IAAM,cAAc;AAEb,SAAS,UAAU,KAAqB;AAC7C,QAAM,EAAE,UAAU,QAAQ,MAAM,IAAI,IAAI,IAAI,KAAK,WAAW;AAE5D,SAAO,WAAW;AACpB;AAQO,SAAS,WAAW,KAAsB;AAC/C,QAAM,EAAE,aAAa,IAAI,IAAI,IAAI,KAAK,WAAW;AAEjD,SAAO,aAAa,IAAI,UAAU;AACpC;AAEO,SAAS,aAAa,KAA4B;AACvD,QAAM,EAAE,aAAa,IAAI,IAAI,IAAI,KAAK,WAAW;AAEjD,SAAO,aAAa,IAAI,UAAU;AACpC;AAEO,SAAS,eAAe,KAAqB;AAClD,QAAM,SAAS,IAAI,IAAI,KAAK,WAAW;AACvC,SAAO,aAAa,IAAI,UAAU,MAAM;AAExC,SAAO,OAAO,KAAK,QAAQ,OAAO,QAAQ,EAAE;AAC9C;AAEO,SAAS,cAAc,KAAqB;AACjD,QAAM,SAAS,IAAI,IAAI,KAAK,WAAW;AACvC,SAAO,aAAa,OAAO,UAAU;AAErC,SAAO,OAAO,KAAK,QAAQ,OAAO,QAAQ,EAAE;AAC9C;AAQO,SAAS,aAAa,KAAsB;AACjD,QAAM,SAAS,IAAI,IAAI,KAAK,WAAW;AACvC,SAAO,aAAa,OAAO,UAAU;AACrC,SAAO,aAAa,OAAO,QAAQ;AAEnC,SAAO,UAAU,OAAO,SAAS,CAAC;AACpC;AAEO,SAAS,YAAY,KAAqB;AAC/C,QAAM,SAAS,IAAI,IAAI,KAAK,WAAW;AACvC,SAAO,OAAO;AAEd,SAAO,OAAO,KAAK,QAAQ,OAAO,QAAQ,EAAE;AAC9C;AAEO,SAAS,aAAa,KAAqB;AAChD,QAAM,UAAU,CAAC,aAAa,cAAc;AAE5C,SAAO,QAAQ,OAAO,CAAC,MAAM,MAAM,EAAE,IAAI,GAAG,GAAG;AACjD;;;AC9DA,IAAM,eAAe;AAErB,IAAM,eAAN,cAA2B,MAAM;AAAA,EAC/B,YAAY,SAAiB;AAC3B,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACd;AACF;AASA,SAAS,MAAM,MAAoB,MAA0B;AAC3D,QAAM,UAAU,iBAAiB,IAAI;AACrC,MAAI,SAAoB;AACxB,MAAI;AAEJ,OAAK,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;AACnC,UAAM,MAAM,QAAQ,CAAC;AAErB,QAAI,OAAO,WAAW,YAAY,WAAW,MAAM;AACjD,UAAI,CAAC,MAAM,QAAQ,MAAM,KAAK,aAAa,KAAK,GAAG,GAAG;AACpD,cAAM,IAAI;AAAA,UACR,iDAAiD,GAAG;AAAA,QACtD;AAAA,MACF;AAEA,eAAS,MAAM,QAAQ,GAAG;AAAA,IAC5B,OAAO;AACL,YAAM,IAAI;AAAA,QACR,6CAA6C,KAAK,UAAU,MAAM,CAAC;AAAA,MACrE;AAAA,IACF;AAAA,EACF;AAEA,MAAI,MAAM,QAAQ,QAAQ;AACxB,WAAO;AAAA,EACT,OAAO;AACL,WAAO;AAAA,EACT;AACF;AAMA,SAAS,OAAO,MAAoB,KAAsC;AACxE,MAAI,MAAM,QAAQ,IAAI,KAAK,OAAO,MAAM,OAAO,GAAG,CAAC,GAAG;AACpD,UAAM,YAAY,MAAM,KAAK,IAAI,MAAM,GAAG,CAAC;AAC3C,UAAM,OAAO,UAAU,CAAC;AACxB,UAAM,KAAK,UAAU,CAAC;AAEtB,QAAI,CAAC,MAAM,CAAC,MAAM;AAChB,aAAO;AAAA,IACT;AAEA,QAAI;AACJ,QAAI;AAEJ,SAAK,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AAChC,cAAQ,KAAK,CAAC;AACd,UACE,OAAO,UAAU,YACjB,CAAC,MAAM,QAAQ,KAAK,KACpB,UAAU,MACV;AACA,cAAM,MAAM,MAAM,IAAI;AACtB,YAAI,OAAO,IAAI,SAAS,MAAM,IAAI;AAChC;AAAA,QACF;AAAA,MACF,OAAO;AACL,cAAM,IAAI,aAAa,wBAAwB,GAAG,OAAO,KAAK,EAAE;AAAA,MAClE;AAAA,IACF;AAEA,QAAI,MAAM,KAAK,QAAQ;AACrB,YAAM,IAAI,aAAa,kBAAkB,GAAG,sBAAsB;AAAA,IACpE;AAEA,WAAO;AAAA,EACT,OAAO;AACL,WAAO;AAAA,EACT;AACF;AAEA,SAAS,MAAM,MAAoB,KAAa;AAC9C,QAAM,YAAY,OAAO,MAAM,GAAG;AAElC,MAAI,MAAM,QAAQ,IAAI,GAAG;AACvB,WAAO,KAAK,SAAmB;AAAA,EACjC,OAAO;AACL,WAAO,KAAK,SAAS;AAAA,EACvB;AACF;AAEA,SAAS,iBAAiB,MAAwB;AAChD,MAAI,OAAO,SAAS,UAAU;AAC5B,WAAO,KAAK,QAAQ,MAAM,EAAE;AAC5B,QAAI,SAAS,IAAI;AACf,aAAO,CAAC;AAAA,IACV;AAEA,WAAO,KAAK,MAAM,GAAG;AAAA,EACvB,OAAO;AACL,WAAO;AAAA,EACT;AACF;;;ACnHO,IAAM,SAAS;AAAA,EACpB,SAAS;AAAA,EACT,UAAU;AACZ;;;ACCO,SAAS,gBAAgB,KAAwB;AACtD,SAAO,eAAe,GAAG,KAAK,CAAC,gBAAgB,GAAG;AACpD;AAEO,SAAS,eAAe,KAAwB;AACrD,QAAM,cAAc,IAAI,QAAQ,IAAI,cAAc;AAClD,QAAM,YAAY;AAElB,SAAO,CAAC,EAAE,eAAe,YAAY,MAAM,SAAS;AACtD;AAEA,SAAS,gBAAgB,KAAwB;AAC/C,QAAM,cAAc,IAAI,QAAQ,IAAI,qBAAqB;AAEzD,SAAO,CAAC,EAAE,eAAe,YAAY,MAAM,aAAa,MAAM;AAChE;AAEA,IAAM,yBAAN,cAAqC,MAAM;AAAA,EAGzC,YAAY,SAAiB;AAC3B,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACd;AACF;AAEO,SAAS,iBAAiB,MAAsC;AACrE,QAAM,EAAE,IAAI,IAAI;AAChB,MAAI,gBAAgB,GAAG,GAAG;AACxB,WAAO;AAAA,EACT,OAAO;AACL,UAAM,QAAQ,IAAI,uBAAuB,4BAA4B;AACrE,UAAM,WAAW;AACjB,UAAM;AAAA,EACR;AACF;AAEO,SAAS,mBAAmB,MAAsC;AACvE,QAAM,EAAE,IAAI,IAAI;AAChB,MAAI,CAAC,IAAI,MAAM,IAAI,WAAW,KAAK;AACjC,QAAI,IAAI,WAAW,KAAK;AACtB,cAAQ;AAAA,QACN;AAAA,MAMF;AAAA,IACF;AACA,UAAM,QAAQ,IAAI,uBAAuB,IAAI,UAAU;AACvD,UAAM,WAAW;AACjB,UAAM;AAAA,EACR;AACA,SAAO;AACT;AAEO,SAAS,aACd,UACAA,YACA;AAAA,EACE,SAAS;AAAA,EACT,UAAU,CAAC;AAAA,EACX,OAAO;AAAA,EACP;AAAA,EACA,GAAG;AACL,IAAsB,CAAC,GACK;AAC5B,WAAS,OAAO,YAAY;AAC5B,QAAM,eAAe,SAAS,EAAE;AAEhC,QAAM,cAAc,EAAE,GAAG,QAAQ;AACjC,cAAY,kBAAkB,IAAI;AAClC,cAAY,QAAQ,IAAI;AACxB,cAAY,qBAAqB,IAAI;AAErC,MAAI,UAAU,SAAS,UAAU,QAAQ;AACvC,gBAAY,cAAc,IAAI;AAAA,EAChC;AAEA,MAAI,gBAAgB,UAAU;AAC5B,WAAO,YAAY,cAAc;AAAA,EACnC;AAEA,MAAI,aAAa,WAAW;AAC1B,gBAAY,cAAc,IAAI,aAAa;AAAA,EAC7C;AAEA,QAAM,YAAY,IAAI,IAAI,aAAaA,UAAS,GAAG,OAAO,OAAO;AAEjE,QAAM,cAAc;AAEpB,MAAI,EAAE,UAAU,SAAS,UAAU,SAAS;AAC1C,gBAAY,wBAAwB,IAAI;AACxC,aAAS;AAAA,EACX;AAEA,QAAM,UAA4B;AAAA,IAChC;AAAA,IACA,SAAS;AAAA,IACT;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,MAAI,aAAa,gBAAgB;AAC/B,UAAM,WAAW,IAAI,IAAI,aAAa,gBAAgB,OAAO,OAAO;AAEpE,YAAQ,WAAW,SAAS,SAAS;AAAA,EACvC;AAEA,MAAI,UAAU,SAAS,UAAU,QAAQ;AACvC,QAAI,QAAQ,gBAAgB,UAAU;AACpC,YAAM,UAAU,IAAI;AAAA,QAClB,QAAQ;AAAA,MACV;AAKA,cAAQ,QAAQ,CAAC,OAAO,QAAQ,UAAU,aAAa,OAAO,GAAG,CAAC;AAClE,cAAQ,QAAQ,CAAC,OAAO,QAAQ,UAAU,aAAa,OAAO,KAAK,KAAK,CAAC;AAAA,IAC3E;AAEA,WAAO,QAAQ;AAAA,EACjB;AAEA,SAAO,CAAC,UAAU,SAAS,GAAG,EAAE,GAAG,SAAS,GAAG,KAAK,CAAC;AACvD;AAEO,SAAS,YAAY,KAA4C;AACtE,SAAO,IACJ,KAAK,EACL,KAAK,CAAC,SAAS;AACd,WAAO,EAAE,KAAK,KAAK;AAAA,EACrB,CAAC,EACA,MAAM,CAAC,MAAM;AACZ,MAAE,WAAW;AACb,UAAM;AAAA,EACR,CAAC;AACL;AAEO,SAAS,cAAc,KAA4C;AACxE,SAAO,QAAQ,QAAQ,GAAG,EACvB,KAAK,WAAW,EAChB,KAAK,kBAAkB,EACvB,KAAK,gBAAgB;AAC1B;;;ACvJO,SAAS,aACd,YACA,WACS;AACT,MAAI,cAAc,WAAW;AAC3B,UAAM,eAAe,CAAC,UAAU,MAAM,CAAC,UAAU,WAAW,SAAS,KAAK,CAAC;AAC3E,WAAO;AAAA,EACT,OAAO;AACL,WAAO;AAAA,EACT;AACF;;;ACVA,qBAA6B;AAWtB,IAAM,iBAAiB;AACvB,IAAM,mBAAmB;AAEzB,IAAM,mBAAe;AAAA,EAC1B;AAAA,EACA,CAAC,EAAE,SAAS,KAAK,MAAgD;AAC/D,cAAU,aAAa,OAAO;AAE9B,WAAO;AAAA,MACL,SAAS;AAAA,QACP;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAEO,IAAM,kBAAc;AAAA,EACzB;AAAA,EACA,CAAC,EAAE,SAAS,KAAK,MAAgD;AAC/D,cAAU,aAAa,OAAO;AAE9B,WAAO;AAAA,MACL,SAAS;AAAA,QACP;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAEO,IAAM,qBAAiB;AAAA,EAC5B;AACF;AAmBO,IAAM,sBAAkB,6BAM5B,8BAA8B;AAgB1B,IAAM,eAAW;AAAA,EACtB;AACF;AAWO,IAAM,iBAAa;AAAA,EACxB;AACF;AAgBO,IAAM,kBAAc;AAAA,EACzB;AACF;AAgBO,IAAM,kBAAc,6BAGxB,0BAA0B;AAgBtB,IAAM,mBAAe,6BAGzB,2BAA2B;AAEvB,IAAM,mBAAe,6BAEzB,4BAA4B;AAExB,IAAM,oBAAgB,6BAE1B,4BAA4B;AAExB,IAAM,oBAAgB,6BAE1B,6BAA6B;;;ACzIhC,SAAS,eACP,KACA,WACA,UACO;AACP,WAAS,eAAe,EAAE,SAAS,IAAI,QAAQ,CAAC,CAAC;AACjD,QAAM;AACR;AAEA,SAAS,UACP,SACA,MACA,OACA,KACA,WACM;AACN,QAAM,EAAE,QAAQ,WAAW,IAAI;AAC/B,QAAM,EAAE,QAAQ,WAAW,IAAI;AAE/B,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,YAAY,IAAI;AAAA,IAChB;AAAA,IACA;AAAA,IACA,qBAAqB,KAAK;AAAA,IAC1B,cAAc,aAAa,YAAY,UAAU;AAAA,EACnD;AACF;AAEO,IAAM,2BAAN,cAAuC,MAAM;AAAA,EAClD,YAAY,SAAiB;AAC3B,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACd;AACF;AAEO,IAAM,SAAwB,CACnC,MACA;AAAA,EACE,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,aAAa,CAAC,UAAgB,iBAA+B;AAAA,EAC7D,GAAG;AACL,IAAI,CAAC,MACF;AACH,kBAAgB,iBAAiB,aAAa,aAAa;AAE3D,SAAO,CAAC,UAAU,aAAa;AAC7B,UAAM,YAAY,aAAa,UAAU,MAAM,IAAI;AACnD,UAAM,iBAAiB,SAAS,EAAE,UAAU;AAE5C,aAAS,aAAa,EAAE,gBAAgB,UAAU,CAAC,CAAC;AACpD,aAAS,YAAY,EAAE,UAAU,CAAC,CAAC;AAEnC,WAAO,MAAM,GAAG,SAAS,EACtB,KAAK,aAAa,EAClB,KAAK,CAAC,EAAE,KAAK,KAAK,MAAM;AACvB,YAAM,EAAE,WAAW,QAAQ,CAAC,EAAE,IAAI,SAAS;AAE3C,UAAI;AACJ,UAAI,kBAAkB,QAAW;AAC/B,cAAM,QAAQ,UAAU,CAAC,EAAE,WAAW;AACtC,kBAAU,iBAAiB,KAAK,OAAO,cAAc;AAAA,MACvD,OAAO;AACL,kBAAU;AAAA,MACZ;AAEA,YAAM,OAAO,UAAU,SAAS,MAAM,WAAW,KAAK,SAAS;AAE/D,YAAM,aAAa,MAAM,OAAO,GAAG;AACnC,YAAM,aAAa,KAAK;AACxB,UAAI,CAAC,CAAC,cAAc,cAAc,cAAc,CAAC,OAAO;AACtD,cAAM,UAAU;AAAA,oBACN,cAAc;AAAA,MAC5B,UAAU;AAAA,0BACU,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GAOjC,UAAU,QAAQ,aAAa,IAAI,CAAC,WAAW,UAAU;AAAA,sDACN,UAAU;AAAA;AAAA;AAAA;AAAA;AAKtD,cAAM,IAAI,yBAAyB,OAAO;AAAA,MAC5C;AAEA,YAAM,OAAO,WAAW,MAAM,OAAO,GAAG,IAAI;AAC5C,aAAO,SAAS,mBAAmB,SAAS,IAAI,CAAC,EAAE,KAAK,MAAM,IAAI;AAAA,IACpE,CAAC,EACA,MAAM,CAAC,MAAM,eAAe,GAAG,WAAW,QAAQ,CAAC;AAAA,EACxD;AACF;AAEA,IAAI,sBAAsB;AAAA;AAAA,EAExB,OAAO,CAAC,YAAoB;AAAA,EAE5B;AACF;AAEO,IAAM,QAAsB,CACjC,MACA;AAAA,EACE;AAAA,EACA,aAAa,CAAC,UAAgB,iBAA+B;AAAA,EAC7D,UAAU;AAAA,EACV,GAAG;AACL,IAAI,CAAC,MACF;AACH,SAAO,CAAC,UAAU,aAAa;AAC7B,UAAM,iBAAiB,SAAS,EAAE,UAAU;AAC5C,qBACG,kBAAkB,aAAa,cAAc,KAAM;AACtD,UAAM,iBAAiB,kBAAkB,SAAS,EAAE;AAEpD,QAAI,WAAW,IAAI,KAAK,CAAC,gBAAgB;AACvC,cAAQ;AAAA,QACN,uCAAuC,cAAc;AAAA,MACvD;AACA,aAAO,cAAc,IAAI;AAAA,IAC3B;AAEA,UAAM,aAAa,IAAI,gBAAgB;AACvC,UAAM,EAAE,OAAO,IAAI;AACnB,UAAM,YAAY,aAAa,UAAU,MAAM;AAAA,MAC7C,GAAG;AAAA,MACH;AAAA,IACF,CAAC;AAED,aAAS,YAAY,EAAE,gBAAgB,UAAU,CAAC,CAAC;AACnD,aAAS,YAAY,EAAE,UAAU,CAAC,CAAC;AAEnC,wBAAoB;AAAA,MAClB;AAAA,IACF;AACA,0BAAsB;AAEtB,WAAO,MAAM,GAAG,SAAS,EACtB,KAAK,aAAa,EAClB,KAAK,CAAC,EAAE,KAAK,KAAK,MAAM;AACvB,YAAM,EAAE,WAAW,QAAQ,CAAC,EAAE,IAAI,SAAS;AAC3C,YAAM,QAAQ,UAAU,CAAC,EAAE,WAAW;AACtC,YAAM,UAAU,iBAAiB,KAAK,OAAO,cAAc;AAC3D,UAAI,kBAAkB,WAAW,IAAI,KAAK,gBAAgB;AACxD,cAAM,aAAa,MAAM,cAAc,GAAG;AAC1C,cAAM,aAAa,KAAK;AACxB,YAAI,CAAC,CAAC,cAAc,cAAc,YAAY;AAC5C,gBAAM,UAAU;AAAA,uBACL,UAAU;AAAA,uBACV,UAAU,gBAAgB,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GAO5D,UAAU,QAAQ,aAAa,IAAI,CAAC,WAAW,UAAU;AAAA,sDACN,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAMpD,gBAAM,IAAI,yBAAyB,OAAO;AAAA,QAC5C;AACA,iBAAS,SAAS,EAAE,MAAM,gBAAgB,IAAI,QAAQ,CAAC,CAAC;AAAA,MAC1D;AAEA,YAAM,OAAO,UAAU,SAAS,MAAM,WAAW,KAAK,SAAS;AAE/D,YAAM,YAAuB;AAAA,QAC3B,GAAG;AAAA,QACH,kBAAkB;AAAA,UAChB;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF;AAAA,MACF;AAEA,YAAM,OAAO,WAAW,MAAM,OAAO,GAAG,IAAI;AAC5C,aAAO,SAAS,mBAAmB,SAAS,IAAI,CAAC,EAAE,KAAK,MAAM,SAAS;AAAA,IACzE,CAAC,EACA,MAAM,CAAC,MAAM,eAAe,GAAG,WAAW,QAAQ,CAAC;AAAA,EACxD;AACF;AAEA,SAAS,mBACP,MACA,KACA,OACA,SACA,gBACA,SACA;AACA,MAAI,mBAAqC;AACzC,MAAI,CAAC,IAAI,cAAc,CAAC,OAAO;AAC7B,uBAAmB;AAAA,EACrB;AACA,QAAM,aAAa,WAAW;AAC9B,MAAI,YAAY;AACd,uBAAmB;AAAA,EACrB;AACA,MAAI,WAAW,OAAO;AACpB,QAAI,IAAI,YAAY;AAClB,yBAAmB;AAAA,IACrB,OAAO;AACL,yBAAmB;AAAA,IACrB;AAAA,EACF;AAEA,SAAO;AACT;AAEA,SAAS,iBACP,KACA,OACA,gBACA;AACA,MAAI,UAAU,aAAa,IAAI,GAAG;AAClC,MAAI,CAAC,SAAS,CAAC,IAAI,YAAY;AAC7B,cAAU;AAAA,EACZ;AAEA,QAAM,kBAAkB,IAAI,QAAQ,IAAI,kBAAkB;AAC1D,MAAI,iBAAiB;AACnB,cAAU,aAAa,eAAe;AAAA,EACxC;AACA,SAAO;AACT;;;APzPA,SAAS,gBACP,SACA,SAAkB,CAAC,GACH;AAChB,YAAU,aAAa,OAAO;AAC9B,SAAO,CAAC,aAAa;AACnB,UAAM,UAAU,OACb,OAAO,CAAC,EAAE,KAAK,MAAM,SAAS,MAAM,EACpC,IAAI,SAAU;AAAA,MACb;AAAA,MACA,gBAAgB;AAAA,MAChB,aAAa;AAAA,IACf,GAAG;AAGD,YAAM,UAAU,aAAa,GAAG;AAEhC,aAAO,SAAS,OAAO,KAAK,EAAE,QAAQ,CAAC,CAAC,EACrC,KAAK,MAAM;AACV,iBAAS;AAAA,UACP,MAAM;AAAA,UACN,SAAS;AAAA,YACP;AAAA,YACA;AAAA,UACF;AAAA,QACF,CAAC;AAAA,MACH,CAAC,EACA,MAAM,CAAC,QAAQ;AACd,iBAAS;AAAA,UACP,MAAM;AAAA,UACN,SAAS;AAAA,YACP;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,UACF;AAAA,QACF,CAAC;AAAA,MACH,CAAC;AAAA,IACL,CAAC;AAEH,WAAO,QAAQ,IAAI,OAAO;AAAA,EAC5B;AACF;AASO,SAAS,mBACd,SACA,MACyB;AACzB,SAAO,CAAC,UAAU,aAAa;AAC7B,cAAU,aAAa,OAAO;AAE9B,UAAM,EAAE,SAAS,CAAC,EAAE,IAAI;AAExB,QAAI,YAAY,MAAM;AACpB,YAAM,WAAW,SAAS,EAAE,MAAM,OAAO;AACzC,eAAS,YAAY,EAAE,SAAS,KAAK,CAAC,CAAC;AACvC,YAAM,cAAc,SAAS,EAAE,MAAM,OAAO;AAE5C,kBAAY,UAAU,QAAQ,CAAC,aAAa;AAC1C,cAAM,EAAE,MAAM,KAAK,IAAI;AAGvB,cAAM,kBAAkB,MAAM,aAAa,IAAI;AAC/C,cAAM,eAAe,MAAM,UAAU,IAAI;AACzC,YAAI,CAAC,cAAc;AACjB;AAAA,YACE,gBAAgB;AAAA,cACd,MAAM;AAAA,cACN;AAAA,cACA,OAAO;AAAA,cACP;AAAA,YACF,CAAC;AAAA,UACH;AAAA,QACF,WAAW,oBAAoB,cAAc;AAC3C;AAAA,YACE,gBAAgB;AAAA,cACd,MAAM;AAAA,cACN;AAAA,cACA,OAAO;AAAA,cACP,eAAe;AAAA,cACf;AAAA,YACF,CAAC;AAAA,UACH;AAAA,QACF;AAAA,MACF,CAAC;AAAA,IACH,OAAO;AACL,eAAS,aAAa,EAAE,SAAS,KAAK,CAAC,CAAC;AACxC,YAAM,cAAc,SAAS,EAAE,MAAM,OAAO;AAE5C,kBAAY,UAAU,QAAQ,CAAC,aAAa;AAC1C,cAAM,EAAE,MAAM,KAAK,IAAI;AACvB,cAAM,kBAAkB,MAAM,aAAa,IAAI;AAE/C;AAAA,UACE,gBAAgB;AAAA,YACd,MAAM;AAAA,YACN;AAAA,YACA,OAAO;AAAA,YACP;AAAA,UACF,CAAC;AAAA,QACH;AAAA,MACF,CAAC;AAAA,IACH;AAEA,UAAM,WAAW,OAAO,SAAS;AACjC,QAAI,UAAU;AACZ,aAAO,SAAS,gBAAgB,SAAS,MAAM,CAAC,EAAE;AAAA,QAAK,MACrD,QAAQ,QAAQ;AAAA,MAClB;AAAA,IACF,OAAO;AACL,aAAO,QAAQ,QAAQ;AAAA,IACzB;AAAA,EACF;AACF;","names":["pathQuery"]}
|
|
1
|
+
{"version":3,"sources":["../../lib/action_creators/index.ts","../../lib/utils/url.ts","../../lib/utils/immutability.ts","../../lib/config.ts","../../lib/utils/limited_set.ts","../../lib/utils/request.ts","../../lib/utils/window.ts","../../lib/actions.ts","../../lib/action_creators/requests.ts","../../lib/action_creators/stream.ts"],"sourcesContent":["import { urlToPageKey, getIn, setIn, propsAtParam } from '../utils'\nimport {\n saveResponse,\n GRAFTING_ERROR,\n GRAFTING_SUCCESS,\n handleGraft,\n saveFragment,\n handleFragmentGraft,\n} from '../actions'\nimport { remote } from './requests'\nimport {\n SaveAndProcessPageThunk,\n DefermentThunk,\n Defer,\n JSONMappable,\n PageResponse,\n} from '../types'\nimport { handleStreamResponse } from './stream'\nexport * from './requests'\n\nfunction fetchDeferments(\n pageKey: string,\n defers: Defer[] = []\n): DefermentThunk {\n pageKey = urlToPageKey(pageKey)\n return (dispatch) => {\n const fetches = defers\n .filter(({ type }) => type === 'auto')\n .map(function ({\n url,\n successAction = GRAFTING_SUCCESS,\n failAction = GRAFTING_ERROR,\n }) {\n // props_at will always be present in a graft response\n // That's why this is marked `as string`\n const keyPath = propsAtParam(url) as string\n\n return dispatch(remote(url, { pageKey }))\n .then(() => {\n dispatch({\n type: successAction,\n payload: {\n pageKey,\n keyPath,\n },\n })\n })\n .catch((err) => {\n dispatch({\n type: failAction,\n payload: {\n url,\n err,\n pageKey,\n keyPath,\n },\n })\n })\n })\n\n return Promise.all(fetches)\n }\n}\n\n/**\n * Save and process a rendered view from PropsTemplate. This is the primitive\n * function that `visit` and `remote` calls when it receives a page.\n *\n * If you render a page outside the normal request response cycle, e.g,\n * websocket, you can use this function to save the payload.\n */\nexport function saveAndProcessPage(\n pageKey: string,\n page: PageResponse\n): SaveAndProcessPageThunk {\n return (dispatch) => {\n pageKey = urlToPageKey(pageKey)\n\n let nextPage = page\n\n page.fragments.reverse().forEach((fragment) => {\n const { id, path } = fragment\n const node = getIn(nextPage, path) as JSONMappable\n nextPage = setIn(page, path, { __id: id })\n\n dispatch(\n saveFragment({\n fragmentId: id,\n data: node,\n })\n )\n })\n\n if (nextPage.action === 'graft') {\n if (typeof nextPage.fragmentContext === 'string') {\n dispatch(\n handleFragmentGraft({\n fragmentId: nextPage.fragmentContext,\n response: nextPage,\n })\n )\n } else {\n dispatch(handleGraft({ pageKey, page: nextPage }))\n }\n } else if (nextPage.action === 'handleStreamResponse') {\n // We resolve the promise here because fragment responses\n // have deferment disabled.\n dispatch(handleStreamResponse(nextPage))\n return Promise.resolve()\n } else {\n dispatch(saveResponse({ pageKey, page: nextPage }))\n }\n\n const hasFetch = typeof fetch != 'undefined'\n if (hasFetch) {\n return dispatch(fetchDeferments(pageKey, nextPage.defers)).then(() =>\n Promise.resolve()\n )\n } else {\n return Promise.resolve()\n }\n }\n}\n","import { PageKey } from '../types'\n\nconst FAKE_ORIGIN = 'https://example.com'\n\nexport function pathQuery(url: string): string {\n const { pathname, search: query } = new URL(url, FAKE_ORIGIN)\n\n return pathname + query\n}\n\nexport function pathQueryHash(url: string): string {\n const { pathname, hash, search: query } = new URL(url, FAKE_ORIGIN)\n\n return pathname + query + hash\n}\n\nexport function hasPropsAt(url: string): boolean {\n const { searchParams } = new URL(url, FAKE_ORIGIN)\n\n return searchParams.has('props_at')\n}\n\nexport function propsAtParam(url: string): string | null {\n const { searchParams } = new URL(url, FAKE_ORIGIN)\n\n return searchParams.get('props_at')\n}\n\nexport function withFormatJson(url: string): string {\n const parsed = new URL(url, FAKE_ORIGIN)\n parsed.searchParams.set('format', 'json')\n\n return parsed.href.replace(parsed.origin, '')\n}\n\nexport function removePropsAt(url: string): string {\n const parsed = new URL(url, FAKE_ORIGIN)\n parsed.searchParams.delete('props_at')\n\n return parsed.href.replace(parsed.origin, '')\n}\n\n/**\n * Converts a url to a PageKey.\n *\n * @param url\n * @returns\n */\nexport function urlToPageKey(url: string): PageKey {\n const parsed = new URL(url, FAKE_ORIGIN)\n parsed.searchParams.delete('props_at')\n parsed.searchParams.delete('format')\n\n return pathQuery(parsed.toString())\n}\n\nexport function withoutHash(url: string): string {\n const parsed = new URL(url, FAKE_ORIGIN)\n parsed.hash = ''\n\n return parsed.href.replace(parsed.origin, '')\n}\n\nexport function formatForXHR(url: string): string {\n const formats = [withoutHash, withFormatJson]\n\n return formats.reduce((memo, f) => f(memo), url)\n}\n\nexport function parsePageKey(pageKey: PageKey) {\n const { pathname, searchParams } = new URL(pageKey, FAKE_ORIGIN)\n\n const search = Object.fromEntries(searchParams)\n\n return {\n pathname,\n search,\n }\n}\n","// These were taken from Scour.js\n// Then, modified to respect the id=0 keypath\n\nimport { JSONMappable, JSONValue, Keypath } from '../types'\n\nconst canLookAhead = /^[\\da-zA-Z\\-_]+=[\\da-zA-Z\\-_]+$/\n\nclass KeyPathError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'KeyPathError'\n }\n}\n\n/**\n * Retrieves data from a JSON object using a {@link Keypath}\n *\n * @param node\n * @param path\n * @returns\n */\nfunction getIn(node: JSONMappable, path: Keypath): JSONValue {\n const keyPath = normalizeKeyPath(path)\n let result: JSONValue = node\n let i: number\n\n for (i = 0; i < keyPath.length; i++) {\n const key = keyPath[i]\n\n if (typeof result === 'object' && result !== null) {\n if (!Array.isArray(result) && canLookAhead.test(key)) {\n throw new KeyPathError(\n `Expected to find an Array when using the key: ${key}`\n )\n }\n\n result = atKey(result, key)\n } else {\n throw new KeyPathError(\n `Expected to traverse an Array or Obj, got ${JSON.stringify(result)}`\n )\n }\n }\n\n if (i === keyPath.length) {\n return result\n } else {\n return undefined\n }\n}\n\nfunction clone(node: JSONMappable): JSONMappable {\n return Array.isArray(node) ? [].slice.call(node) : { ...node }\n}\n\nfunction getKey(node: JSONMappable, key: string): string | number | never {\n if (Array.isArray(node) && Number.isNaN(Number(key))) {\n const key_parts = Array.from(key.split('='))\n const attr = key_parts[0]\n const id = key_parts[1]\n\n if (!id || !attr) {\n return key\n }\n\n let i: number\n let child: JSONValue\n\n for (i = 0; i < node.length; i++) {\n child = node[i]\n if (\n typeof child === 'object' &&\n !Array.isArray(child) &&\n child !== null\n ) {\n const val = child[attr]\n if (val && val.toString() === id) {\n break\n }\n } else {\n throw new KeyPathError(`Could not look ahead ${key} at ${child}`)\n }\n }\n\n if (i === node.length) {\n throw new KeyPathError(`Could not find ${key} while looking ahead`)\n }\n\n return i\n } else {\n return key\n }\n}\n\nfunction atKey(node: JSONMappable, key: string) {\n const actualKey = getKey(node, key)\n\n if (Array.isArray(node)) {\n return node[actualKey as number]\n } else {\n return node[actualKey]\n }\n}\n\nfunction normalizeKeyPath(path: string): string[] {\n if (typeof path === 'string') {\n path = path.replace(/ /g, '')\n if (path === '') {\n return []\n }\n\n return path.split('.')\n } else {\n return path\n }\n}\n/**\n * Sets data into a JSON object using a {@link Keypath}\n *\n * @param object\n * @param path\n * @param value\n * @returns\n */\nfunction setIn<T extends JSONMappable>(\n object: T,\n path: string,\n value: JSONValue\n): T | never {\n const keypath = normalizeKeyPath(path)\n\n const results: {\n 0: T\n [key: number]: JSONValue\n } = { 0: object }\n\n const parents: {\n 0: T\n [key: number]: JSONValue\n } = { 0: object }\n\n let i: number\n\n for (i = 0; i < keypath.length; i++) {\n const parent = parents[i]\n\n if (!(typeof parent === 'object' && parent !== null)) {\n throw new KeyPathError(\n `Expected to traverse an Array or Obj, got ${JSON.stringify(parent)}`\n )\n }\n\n const child = atKey(parent, keypath[i])\n parents[i + 1] = child\n }\n\n results[keypath.length] = value\n\n for (i = keypath.length - 1; i >= 0; i--) {\n // Parents will always have a JSONValue at\n // keypath.length so this loop skips that one element\n // Every other element in parents is a JSONMappable\n const target = clone(parents[i] as JSONMappable)\n results[i] = target\n const key = getKey(results[i] as JSONMappable, keypath[i])\n if (Array.isArray(target)) {\n target[key as number] = results[i + 1]\n } else {\n target[key] = results[i + 1]\n }\n }\n\n return results[0]\n}\n\nexport { getIn, setIn, KeyPathError }\n","export const config = {\n baseUrl: '',\n maxPages: 20,\n}\n","export class LimitedSet extends Set {\n private maxSize: number\n\n constructor(maxSize: number) {\n super()\n this.maxSize = maxSize\n }\n\n add(value: unknown) {\n if (this.size >= this.maxSize) {\n const iterator = this.values()\n const oldestValue = iterator.next().value\n this.delete(oldestValue)\n }\n super.add(value)\n\n return this\n }\n}\n","import { formatForXHR } from './url'\nimport { config } from '../config'\nimport { BasicRequestInit, ParsedResponse, RootState } from '../types'\nimport { LimitedSet } from './limited_set'\nimport { v4 as uuidv4 } from 'uuid'\n\nexport const lastRequestIds = new LimitedSet(20)\n\nexport function isValidResponse(xhr: Response): boolean {\n return isValidContent(xhr) && !downloadingFile(xhr)\n}\n\nexport function isValidContent(rsp: Response): boolean {\n const contentType = rsp.headers.get('content-type')\n const jsContent = /^(?:application\\/json)(?:;|$)/\n\n return !!(contentType && contentType.match(jsContent))\n}\n\nfunction downloadingFile(xhr: Response): boolean {\n const disposition = xhr.headers.get('content-disposition')\n\n return !!(disposition && disposition.match(/^attachment/) !== null)\n}\n\nclass SuperglueResponseError extends Error {\n response: Response\n\n constructor(message: string) {\n super(message)\n this.name = 'SuperglueResponseError'\n }\n}\n\nexport function validateResponse(args: ParsedResponse): ParsedResponse {\n const { rsp } = args\n if (isValidResponse(rsp)) {\n return args\n } else {\n const error = new SuperglueResponseError('Invalid Superglue Response')\n error.response = rsp\n throw error\n }\n}\n\nexport function handleServerErrors(args: ParsedResponse): ParsedResponse {\n const { rsp } = args\n if (!rsp.ok && rsp.status !== 422) {\n if (rsp.status === 406) {\n console.error(\n \"Superglue encountered a 406 Not Acceptable response. This can happen if you used respond_to and didn't specify format.json in the block. Try adding it to your respond_to. For example:\\n\\n\" +\n 'respond_to do |format|\\n' +\n ' format.html\\n' +\n ' format.json\\n' +\n ' format.csv\\n' +\n 'end'\n )\n }\n const error = new SuperglueResponseError(rsp.statusText)\n error.response = rsp\n throw error\n }\n return args\n}\n\nexport function argsForFetch(\n getState: () => RootState,\n pathQuery: string,\n {\n method = 'GET',\n headers = {},\n body = '',\n signal,\n ...rest\n }: BasicRequestInit = {}\n): [string, BasicRequestInit] {\n method = method.toUpperCase()\n const currentState = getState().superglue\n\n const nextHeaders = { ...headers }\n nextHeaders['x-requested-with'] = 'XMLHttpRequest'\n nextHeaders['accept'] = 'application/json'\n nextHeaders['x-superglue-request'] = 'true'\n\n const requestId = uuidv4()\n lastRequestIds.add(requestId)\n nextHeaders['X-Superglue-Request-Id'] = requestId\n\n if (method != 'GET' && method != 'HEAD') {\n nextHeaders['content-type'] = 'application/json'\n }\n\n if (body instanceof FormData) {\n delete nextHeaders['content-type']\n }\n\n if (currentState.csrfToken) {\n nextHeaders['x-csrf-token'] = currentState.csrfToken\n }\n\n const fetchPath = new URL(formatForXHR(pathQuery), config.baseUrl)\n\n const credentials = 'same-origin'\n\n if (!(method == 'GET' || method == 'HEAD')) {\n nextHeaders['x-http-method-override'] = method\n method = 'POST'\n }\n\n const options: BasicRequestInit = {\n method,\n headers: nextHeaders,\n body,\n credentials,\n signal,\n }\n\n if (currentState.currentPageKey) {\n const referrer = new URL(currentState.currentPageKey, config.baseUrl)\n\n options.referrer = referrer.toString()\n }\n\n if (method == 'GET' || method == 'HEAD') {\n if (options.body instanceof FormData) {\n const allData = new URLSearchParams(\n options.body as unknown as Record<string, string>\n )\n\n // Form data should override anything in the URL params First we\n // delete every key. Then append the new keys accounting for\n // duplicate keys that represent structural arrays.\n allData.forEach((value, key) => fetchPath.searchParams.delete(key))\n allData.forEach((value, key) => fetchPath.searchParams.append(key, value))\n }\n\n delete options.body\n }\n\n return [fetchPath.toString(), { ...options, ...rest }]\n}\n\nexport function extractJSON(rsp: Response): PromiseLike<ParsedResponse> {\n return rsp\n .json()\n .then((json) => {\n return { rsp, json }\n })\n .catch((e) => {\n e.response = rsp\n throw e\n })\n}\n\nexport function parseResponse(prm: Response): PromiseLike<ParsedResponse> {\n return Promise.resolve(prm)\n .then(extractJSON)\n .then(handleServerErrors)\n .then(validateResponse)\n}\n","export function needsRefresh(\n prevAssets: string[],\n newAssets: string[]\n): boolean {\n if (prevAssets && newAssets) {\n const hasNewAssets = !newAssets.every((asset) => prevAssets.includes(asset))\n return hasNewAssets\n } else {\n return false\n }\n}\n","import { createAction } from '@reduxjs/toolkit'\nimport {\n FetchArgs,\n PageKey,\n GraftResponse,\n SaveResponse,\n JSONMappable,\n} from './types'\nimport { urlToPageKey } from './utils'\n\nexport const GRAFTING_ERROR = '@@superglue/GRAFTING_ERROR'\nexport const GRAFTING_SUCCESS = '@@superglue/GRAFTING_SUCCESS'\n\nexport const saveResponse = createAction(\n '@@superglue/SAVE_RESPONSE',\n ({ pageKey, page }: { pageKey: string; page: SaveResponse }) => {\n pageKey = urlToPageKey(pageKey)\n\n return {\n payload: {\n pageKey,\n page,\n },\n }\n }\n)\n\nexport const handleGraft = createAction(\n '@@superglue/HANDLE_GRAFT',\n ({ pageKey, page }: { pageKey: string; page: GraftResponse }) => {\n pageKey = urlToPageKey(pageKey)\n\n return {\n payload: {\n page,\n pageKey,\n },\n }\n }\n)\n\nexport const superglueError = createAction<{ message: string }>(\n '@@superglue/ERROR'\n)\n\n/**\n * A redux action you can dispatch to copy a page from one pageKey to another. Its\n * a very useful way to create optimistic updates with a URL change. For example:\n *\n * ```\n * import { copyPage, remote } from '@thoughtbot/superglue'\n *\n * dispatch(copyPage({ from: originalKey, to: targetKey}))\n *\n * ... make edits to target page and finally\n *\n * navigateTo(targetKey)\n * ```\n */\nexport const copyPage = createAction<{ from: PageKey; to: PageKey }>(\n '@@superglue/COPY_PAGE'\n)\n\n/**\n * A redux action you can dispatch to remove a page from your store.\n *\n * ```\n * import { removePage } from '@thoughtbot/superglue'\n *\n * dispatch(removePage({ pageKey: '/delete_me_please\"}))\n * ```\n */\nexport const removePage = createAction<{ pageKey: PageKey }>(\n '@@superglue/REMOVE_PAGE'\n)\n\n/**\n * A redux action called before a `fetch` takes place. It will fire in `remote`\n * and `visit`. You can hook into this event in your redux slices like this:\n *\n * ```\n * import { beforeFetch } from '@thoughtbot/superglue'\n *\n * export const exampleSlice = createSlice({\n * name: 'Example',\n * initialState: {},\n * extraReducers: (builder) => {\n * builder.addCase(beforeFetch, (state, action) => {\n * ```\n */\nexport const beforeFetch = createAction<{ fetchArgs: FetchArgs }>(\n '@@superglue/BEFORE_FETCH'\n)\n\n/**\n * A redux action called before a `visit` takes place. You can hook into this event\n * in your redux slices like this:\n *\n * ```\n * import { beforeVisit } from '@thoughtbot/superglue'\n *\n * export const exampleSlice = createSlice({\n * name: 'Example',\n * initialState: {},\n * extraReducers: (builder) => {\n * builder.addCase(beforeVisit, (state, action) => {\n * ```\n */\nexport const beforeVisit = createAction<{\n currentPageKey: PageKey\n fetchArgs: FetchArgs\n}>('@@superglue/BEFORE_VISIT')\n\n/**\n * A redux action called before `remote` takes place. You can hook into this event\n * in your redux slices like this:\n *\n * ```\n * import { beforeRemote } from '@thoughtbot/superglue'\n *\n * export const exampleSlice = createSlice({\n * name: 'Example',\n * initialState: {},\n * extraReducers: (builder) => {\n * builder.addCase(beforeRemote, (state, action) => {\n * ```\n */\nexport const beforeRemote = createAction<{\n currentPageKey: PageKey\n fetchArgs: FetchArgs\n}>('@@superglue/BEFORE_REMOTE')\n\nexport const setCSRFToken = createAction<{\n csrfToken: string | undefined\n}>('@@superglue/SET_CSRF_TOKEN')\n\nexport const historyChange = createAction<{\n pageKey: PageKey\n}>('@@superglue/HISTORY_CHANGE')\n\nexport const setActivePage = createAction<{\n pageKey: PageKey\n}>('@@superglue/SET_ACTIVE_PAGE')\n\nexport const handleFragmentGraft = createAction(\n '@@superglue/HANDLE_FRAGMENT_GRAFT',\n ({\n fragmentId,\n response,\n }: {\n fragmentId: string\n response: GraftResponse\n }) => {\n return {\n payload: {\n response,\n fragmentId,\n },\n }\n }\n)\n\nexport const saveFragment = createAction(\n '@@superglue/SAVE_FRAGMENT',\n ({ fragmentId, data }: { fragmentId: string; data: JSONMappable }) => {\n return {\n payload: {\n fragmentId,\n data,\n },\n }\n }\n)\n\nexport const appendToFragment = createAction(\n '@@superglue/APPEND_TO_FRAGMENT',\n ({ data, fragmentId }: { data: JSONMappable; fragmentId: string }) => {\n return {\n payload: {\n data,\n fragmentId,\n },\n }\n }\n)\n\nexport const prependToFragment = createAction(\n '@@superglue/PREPEND_TO_FRAGMENT',\n ({ data, fragmentId }: { data: JSONMappable; fragmentId: string }) => {\n return {\n payload: {\n data,\n fragmentId: fragmentId,\n },\n }\n }\n)\n","import {\n argsForFetch,\n parseResponse,\n needsRefresh,\n urlToPageKey,\n hasPropsAt,\n propsAtParam,\n removePropsAt,\n} from '../utils'\nimport {\n beforeFetch,\n beforeVisit,\n beforeRemote,\n copyPage,\n superglueError,\n} from '../actions'\nimport { saveAndProcessPage } from './index'\nimport {\n FetchArgs,\n PageResponse,\n Page,\n SuperglueState,\n Meta,\n Dispatch,\n RemoteCreator,\n VisitCreator,\n NavigationAction,\n VisitMeta,\n BeforeSave,\n} from '../types'\n\nfunction handleFetchErr(\n err: Error,\n fetchArgs: FetchArgs,\n dispatch: Dispatch\n): never {\n dispatch(superglueError({ message: err.message }))\n throw err\n}\n\nfunction buildMeta(\n pageKey: string,\n page: PageResponse,\n state: SuperglueState,\n rsp: Response,\n fetchArgs: FetchArgs\n): Meta {\n const { assets: prevAssets } = state\n const { assets: nextAssets } = page\n\n const meta: Meta = {\n pageKey,\n page,\n redirected: rsp.redirected,\n rsp,\n fetchArgs,\n needsRefresh: needsRefresh(prevAssets, nextAssets),\n }\n\n if (page.action !== 'handleStreamResponse') {\n meta.componentIdentifier = page.componentIdentifier\n }\n\n return meta\n}\n\nexport class MismatchedComponentError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'MismatchedComponentError'\n }\n}\n\nconst defaultBeforeSave: BeforeSave = (prevPage, receivedPage) => receivedPage\n\nexport const remote: RemoteCreator = (\n path,\n {\n pageKey: targetPageKey,\n force = false,\n beforeSave = defaultBeforeSave,\n ...rest\n } = {}\n) => {\n targetPageKey = targetPageKey && urlToPageKey(targetPageKey)\n\n return (dispatch, getState) => {\n const fetchArgs = argsForFetch(getState, path, rest)\n const currentPageKey = getState().superglue.currentPageKey\n\n dispatch(beforeRemote({ currentPageKey, fetchArgs }))\n dispatch(beforeFetch({ fetchArgs }))\n\n return fetch(...fetchArgs)\n .then(parseResponse)\n .then(({ rsp, json }) => {\n const { superglue, pages = {} } = getState()\n\n let pageKey\n if (targetPageKey === undefined) {\n const isGet = fetchArgs[1].method === 'GET'\n pageKey = calculatePageKey(rsp, isGet, currentPageKey)\n } else {\n pageKey = targetPageKey\n }\n\n const meta = buildMeta(pageKey, json, superglue, rsp, fetchArgs)\n\n if (json.action !== 'handleStreamResponse') {\n const existingId = pages[pageKey]?.componentIdentifier\n const receivedId = json.componentIdentifier\n if (!!existingId && existingId != receivedId && !force) {\n const message = `You cannot replace or update an existing page\nlocated at pages[\"${currentPageKey}\"] that has a componentIdentifier\nof \"${existingId}\" with the contents of a page response that has a\ncomponentIdentifier of \"${receivedId}\".\n\nThis can happen if you're using data-sg-remote or remote but your\nresponse redirected to a page with a different componentIdentifier\nthan the target page. \n\nThis limitation exists because the resulting page shape from grafting\n\"${receivedId}\"'s \"${propsAtParam(path)}\" into \"${existingId}\" may not be\ncompatible with the page component associated with \"${existingId}\".\n\nConsider using data-sg-visit, the visit function, or redirect_back to\nthe same page. Or if you're sure you want to proceed, use force: true.\n `\n throw new MismatchedComponentError(message)\n }\n }\n\n const page = beforeSave(pages[pageKey], json)\n return dispatch(saveAndProcessPage(pageKey, page)).then(() => meta)\n })\n .catch((e) => handleFetchErr(e, fetchArgs, dispatch))\n }\n}\n\nlet lastVisitController = {\n /* eslint-disable-next-line @typescript-eslint/no-unused-vars */\n abort: (_reason: string) => {\n // noop\n },\n}\n\nexport const visit: VisitCreator = (\n path,\n {\n placeholderKey,\n beforeSave = (prevPage: Page, receivedPage: PageResponse) => receivedPage,\n revisit = false,\n ...rest\n } = {}\n) => {\n return (dispatch, getState) => {\n const currentPageKey = getState().superglue.currentPageKey\n placeholderKey =\n (placeholderKey && urlToPageKey(placeholderKey)) || currentPageKey\n const hasPlaceholder = placeholderKey in getState().pages\n\n if (hasPropsAt(path) && !hasPlaceholder) {\n console.warn(\n `Could not find placeholder with key ${placeholderKey} in state. The props_at param will be ignored`\n )\n path = removePropsAt(path)\n }\n\n const controller = new AbortController()\n const { signal } = controller\n const fetchArgs = argsForFetch(getState, path, {\n ...rest,\n signal,\n })\n\n dispatch(beforeVisit({ currentPageKey, fetchArgs }))\n dispatch(beforeFetch({ fetchArgs }))\n\n lastVisitController.abort(\n 'Aborting the previous `visit`. There can be one visit at a time. Use `remote` if there is a need for async requests.'\n )\n lastVisitController = controller\n\n return fetch(...fetchArgs)\n .then(parseResponse)\n .then(({ rsp, json }) => {\n const { superglue, pages = {} } = getState()\n const isGet = fetchArgs[1].method === 'GET'\n const pageKey = calculatePageKey(rsp, isGet, currentPageKey)\n\n const meta = buildMeta(pageKey, json, superglue, rsp, fetchArgs)\n\n if (json.action !== 'handleStreamResponse') {\n if (placeholderKey && hasPropsAt(path) && hasPlaceholder) {\n const existingId = pages[placeholderKey]?.componentIdentifier\n const receivedId = json.componentIdentifier\n if (!!existingId && existingId != receivedId) {\n const message = `You received a page response with a\ncomponentIdentifier \"${receivedId}\" that is different than the\ncomponentIdentifier \"${existingId}\" located at ${placeholderKey}.\n\nThis can happen if you're using data-sg-visit or visit with a\nprops_at param, but the response redirected to a page with a\ndifferent componentIdentifier than the target page. \n\nThis limitation exists because the resulting page shape from grafting\n\"${receivedId}\"'s \"${propsAtParam(path)}\" into \"${existingId}\" may not be\ncompatible with the page component associated with \"${existingId}\".\n\nCheck that you're rendering a page with a matching\ncomponentIdentifier, or consider using redirect_back_with_props_at\nto the same page.\n `\n throw new MismatchedComponentError(message)\n }\n dispatch(copyPage({ from: placeholderKey, to: pageKey }))\n }\n }\n const visitMeta: VisitMeta = {\n ...meta,\n navigationAction: calculateNavAction(\n meta,\n rsp,\n json,\n isGet,\n pageKey,\n currentPageKey,\n revisit\n ),\n }\n\n const page = beforeSave(pages[pageKey], json)\n return dispatch(saveAndProcessPage(pageKey, page)).then(() => visitMeta)\n })\n .catch((e) => handleFetchErr(e, fetchArgs, dispatch))\n }\n}\n\nfunction calculateNavAction(\n meta: Meta,\n rsp: Response,\n json: PageResponse,\n isGet: boolean,\n pageKey: string,\n currentPageKey: string,\n revisit: boolean\n) {\n let navigationAction: NavigationAction = 'push'\n\n if (json.action === 'handleStreamResponse') {\n return 'none'\n }\n\n if (!rsp.redirected && !isGet) {\n navigationAction = 'replace'\n }\n const isSamePage = pageKey == currentPageKey\n if (isSamePage) {\n navigationAction = 'none'\n }\n if (revisit && isGet) {\n if (rsp.redirected) {\n navigationAction = 'replace'\n } else {\n navigationAction = 'none'\n }\n }\n\n return navigationAction\n}\n\nfunction calculatePageKey(\n rsp: Response,\n isGet: boolean,\n currentPageKey: string\n) {\n let pageKey = urlToPageKey(rsp.url)\n if (!isGet && !rsp.redirected) {\n pageKey = currentPageKey\n }\n\n const contentLocation = rsp.headers.get('content-location')\n if (contentLocation) {\n pageKey = urlToPageKey(contentLocation)\n }\n return pageKey\n}\n","import { ThunkAction } from 'redux-thunk'\nimport { Action } from '@reduxjs/toolkit'\nimport { setIn, getIn } from '../utils'\nimport { appendToFragment, prependToFragment, saveFragment } from '../actions'\nimport { JSONMappable, RootState, StreamResponse } from '../types'\nimport { StreamMessage } from '../hooks/useStreamSource'\n\nexport type StreamThunk = ThunkAction<void, RootState, undefined, Action>\nexport type StreamHandleThunk = ThunkAction<void, RootState, undefined, Action>\n\nexport interface StreamThunkOptions {\n saveAs?: string\n}\n\n/**\n * Stream thunk equivalent to StreamActions.prepend()\n * Prepends data to specified fragments, optionally saving as a new fragment\n */\nexport const streamPrepend = (\n fragments: string[],\n data: JSONMappable,\n options: StreamThunkOptions = {}\n): StreamThunk => {\n return (dispatch) => {\n if (options.saveAs) {\n const { saveAs } = options\n dispatch(\n saveFragment({\n fragmentId: saveAs,\n data,\n })\n )\n\n fragments.forEach((fragmentId) => {\n dispatch(\n prependToFragment({\n fragmentId,\n data: {\n __id: saveAs,\n },\n })\n )\n })\n } else {\n fragments.forEach((fragmentId) => {\n dispatch(\n prependToFragment({\n fragmentId: fragmentId,\n data: data,\n })\n )\n })\n }\n }\n}\n\n/**\n * Stream thunk equivalent to StreamActions.append()\n * Appends data to specified fragments, optionally saving as a new fragment\n */\nexport const streamAppend = (\n fragments: string[],\n data: JSONMappable,\n options: StreamThunkOptions = {}\n): StreamThunk => {\n return (dispatch) => {\n if (options.saveAs) {\n const { saveAs } = options\n dispatch(\n saveFragment({\n fragmentId: saveAs,\n data,\n })\n )\n\n fragments.forEach((fragmentId) => {\n dispatch(\n appendToFragment({\n fragmentId,\n data: {\n __id: saveAs,\n },\n })\n )\n })\n } else {\n fragments.forEach((fragmentId) => {\n dispatch(\n appendToFragment({\n fragmentId,\n data,\n })\n )\n })\n }\n }\n}\n\n/**\n * Stream thunk equivalent to StreamActions.save()\n * Saves data to a specific fragment\n */\nexport const streamSave = (\n fragment: string,\n data: JSONMappable\n): StreamThunk => {\n return (dispatch) => {\n dispatch(\n saveFragment({\n fragmentId: fragment,\n data,\n })\n )\n }\n}\n\nexport const handleStreamMessage = (rawMessage: string): StreamHandleThunk => {\n return (dispatch) => {\n const message = JSON.parse(rawMessage) as StreamMessage\n\n let nextMessage = message\n\n if (message.handler !== 'refresh') {\n message.fragments.reverse().forEach((fragment) => {\n const { id, path } = fragment\n const node = getIn(nextMessage as JSONMappable, path) as JSONMappable\n nextMessage = setIn(nextMessage, path, { __id: id })\n\n dispatch(\n saveFragment({\n fragmentId: id,\n data: node,\n })\n )\n })\n }\n\n if (nextMessage.action === 'handleStreamMessage') {\n if (nextMessage.handler === 'append') {\n dispatch(\n streamAppend(\n nextMessage.fragmentIds,\n nextMessage.data,\n nextMessage.options\n )\n )\n }\n\n if (nextMessage.handler === 'prepend') {\n dispatch(\n streamPrepend(\n nextMessage.fragmentIds,\n nextMessage.data,\n nextMessage.options\n )\n )\n }\n\n if (nextMessage.handler === 'save') {\n dispatch(streamSave(nextMessage.fragmentIds[0], nextMessage.data))\n }\n }\n }\n}\n\nexport const handleStreamResponse = (\n response: StreamResponse\n): StreamHandleThunk => {\n return (dispatch) => {\n let nextResponse = response\n\n nextResponse.fragments.reverse().forEach((fragment) => {\n const { id, path } = fragment\n const node = getIn(nextResponse as JSONMappable, path) as JSONMappable\n nextResponse = setIn(nextResponse, path, { __id: id })\n\n dispatch(\n saveFragment({\n fragmentId: id,\n data: node,\n })\n )\n })\n\n nextResponse.data.forEach((message) => {\n if (message.handler === 'append') {\n dispatch(\n streamAppend(message.fragmentIds, message.data, message.options)\n )\n }\n\n if (message.handler === 'prepend') {\n dispatch(\n streamPrepend(message.fragmentIds, message.data, message.options)\n )\n }\n\n if (message.handler === 'save') {\n dispatch(streamSave(message.fragmentIds[0], message.data))\n }\n })\n }\n}\n"],"mappings":"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","names":["pathQuery","uuidv4"]}
|