@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.
- 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-EU2SLL5L.mjs} +555 -63
- package/dist/chunk-EU2SLL5L.mjs.map +1 -0
- package/dist/cjs/action_creators.cjs +497 -61
- package/dist/cjs/action_creators.cjs.map +1 -1
- package/dist/cjs/superglue.cjs +6258 -125
- package/dist/cjs/superglue.cjs.map +1 -1
- package/dist/{index-BYr1PoYr.d.mts → index-O_srQ3Nm.d.mts} +56 -16
- package/dist/superglue.d.mts +62 -14
- package/dist/superglue.mjs +5747 -53
- package/dist/superglue.mjs.map +1 -1
- package/package.json +11 -4
- 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,65 @@ 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 receiveResponse = (0, import_toolkit.createAction)(
|
|
398
|
+
"@@superglue/RECEIVE_RESPONSE",
|
|
399
|
+
({ pageKey, response }) => {
|
|
400
|
+
pageKey = urlToPageKey(pageKey);
|
|
401
|
+
return {
|
|
402
|
+
payload: {
|
|
403
|
+
pageKey,
|
|
404
|
+
response
|
|
405
|
+
}
|
|
406
|
+
};
|
|
407
|
+
}
|
|
408
|
+
);
|
|
409
|
+
var appendToFragment = (0, import_toolkit.createAction)(
|
|
410
|
+
"@@superglue/APPEND_TO_FRAGMENT",
|
|
411
|
+
({ data, fragmentId }) => {
|
|
412
|
+
return {
|
|
413
|
+
payload: {
|
|
414
|
+
data,
|
|
415
|
+
fragmentId
|
|
416
|
+
}
|
|
417
|
+
};
|
|
418
|
+
}
|
|
419
|
+
);
|
|
420
|
+
var prependToFragment = (0, import_toolkit.createAction)(
|
|
421
|
+
"@@superglue/PREPEND_TO_FRAGMENT",
|
|
422
|
+
({ data, fragmentId }) => {
|
|
423
|
+
return {
|
|
424
|
+
payload: {
|
|
425
|
+
data,
|
|
426
|
+
fragmentId
|
|
427
|
+
}
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
);
|
|
320
431
|
|
|
321
432
|
// lib/action_creators/requests.ts
|
|
322
433
|
function handleFetchErr(err, fetchArgs, dispatch) {
|
|
@@ -326,15 +437,18 @@ function handleFetchErr(err, fetchArgs, dispatch) {
|
|
|
326
437
|
function buildMeta(pageKey, page, state, rsp, fetchArgs) {
|
|
327
438
|
const { assets: prevAssets } = state;
|
|
328
439
|
const { assets: nextAssets } = page;
|
|
329
|
-
|
|
440
|
+
const meta = {
|
|
330
441
|
pageKey,
|
|
331
442
|
page,
|
|
332
443
|
redirected: rsp.redirected,
|
|
333
444
|
rsp,
|
|
334
445
|
fetchArgs,
|
|
335
|
-
componentIdentifier: page.componentIdentifier,
|
|
336
446
|
needsRefresh: needsRefresh(prevAssets, nextAssets)
|
|
337
447
|
};
|
|
448
|
+
if (page.action !== "handleStreamResponse") {
|
|
449
|
+
meta.componentIdentifier = page.componentIdentifier;
|
|
450
|
+
}
|
|
451
|
+
return meta;
|
|
338
452
|
}
|
|
339
453
|
var MismatchedComponentError = class extends Error {
|
|
340
454
|
constructor(message) {
|
|
@@ -342,10 +456,11 @@ var MismatchedComponentError = class extends Error {
|
|
|
342
456
|
this.name = "MismatchedComponentError";
|
|
343
457
|
}
|
|
344
458
|
};
|
|
459
|
+
var defaultBeforeSave = (prevPage, receivedPage) => receivedPage;
|
|
345
460
|
var remote = (path, {
|
|
346
461
|
pageKey: targetPageKey,
|
|
347
462
|
force = false,
|
|
348
|
-
beforeSave =
|
|
463
|
+
beforeSave = defaultBeforeSave,
|
|
349
464
|
...rest
|
|
350
465
|
} = {}) => {
|
|
351
466
|
targetPageKey = targetPageKey && urlToPageKey(targetPageKey);
|
|
@@ -364,10 +479,11 @@ var remote = (path, {
|
|
|
364
479
|
pageKey = targetPageKey;
|
|
365
480
|
}
|
|
366
481
|
const meta = buildMeta(pageKey, json, superglue, rsp, fetchArgs);
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
482
|
+
if (json.action !== "handleStreamResponse") {
|
|
483
|
+
const existingId = pages[pageKey]?.componentIdentifier;
|
|
484
|
+
const receivedId = json.componentIdentifier;
|
|
485
|
+
if (!!existingId && existingId != receivedId && !force) {
|
|
486
|
+
const message = `You cannot replace or update an existing page
|
|
371
487
|
located at pages["${currentPageKey}"] that has a componentIdentifier
|
|
372
488
|
of "${existingId}" with the contents of a page response that has a
|
|
373
489
|
componentIdentifier of "${receivedId}".
|
|
@@ -383,8 +499,10 @@ compatible with the page component associated with "${existingId}".
|
|
|
383
499
|
Consider using data-sg-visit, the visit function, or redirect_back to
|
|
384
500
|
the same page. Or if you're sure you want to proceed, use force: true.
|
|
385
501
|
`;
|
|
386
|
-
|
|
502
|
+
throw new MismatchedComponentError(message);
|
|
503
|
+
}
|
|
387
504
|
}
|
|
505
|
+
dispatch(receiveResponse({ pageKey, response: json }));
|
|
388
506
|
const page = beforeSave(pages[pageKey], json);
|
|
389
507
|
return dispatch(saveAndProcessPage(pageKey, page)).then(() => meta);
|
|
390
508
|
}).catch((e) => handleFetchErr(e, fetchArgs, dispatch));
|
|
@@ -427,11 +545,13 @@ var visit = (path, {
|
|
|
427
545
|
const { superglue, pages = {} } = getState();
|
|
428
546
|
const isGet = fetchArgs[1].method === "GET";
|
|
429
547
|
const pageKey = calculatePageKey(rsp, isGet, currentPageKey);
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
const
|
|
548
|
+
const meta = buildMeta(pageKey, json, superglue, rsp, fetchArgs);
|
|
549
|
+
if (json.action !== "handleStreamResponse") {
|
|
550
|
+
if (placeholderKey && hasPropsAt(path) && hasPlaceholder) {
|
|
551
|
+
const existingId = pages[placeholderKey]?.componentIdentifier;
|
|
552
|
+
const receivedId = json.componentIdentifier;
|
|
553
|
+
if (!!existingId && existingId != receivedId) {
|
|
554
|
+
const message = `You received a page response with a
|
|
435
555
|
componentIdentifier "${receivedId}" that is different than the
|
|
436
556
|
componentIdentifier "${existingId}" located at ${placeholderKey}.
|
|
437
557
|
|
|
@@ -447,29 +567,34 @@ Check that you're rendering a page with a matching
|
|
|
447
567
|
componentIdentifier, or consider using redirect_back_with_props_at
|
|
448
568
|
to the same page.
|
|
449
569
|
`;
|
|
450
|
-
|
|
570
|
+
throw new MismatchedComponentError(message);
|
|
571
|
+
}
|
|
572
|
+
dispatch(copyPage({ from: placeholderKey, to: pageKey }));
|
|
451
573
|
}
|
|
452
|
-
dispatch(copyPage({ from: placeholderKey, to: pageKey }));
|
|
453
574
|
}
|
|
454
|
-
const meta = buildMeta(pageKey, json, superglue, rsp, fetchArgs);
|
|
455
575
|
const visitMeta = {
|
|
456
576
|
...meta,
|
|
457
577
|
navigationAction: calculateNavAction(
|
|
458
578
|
meta,
|
|
459
579
|
rsp,
|
|
580
|
+
json,
|
|
460
581
|
isGet,
|
|
461
582
|
pageKey,
|
|
462
583
|
currentPageKey,
|
|
463
584
|
revisit
|
|
464
585
|
)
|
|
465
586
|
};
|
|
587
|
+
dispatch(receiveResponse({ pageKey, response: json }));
|
|
466
588
|
const page = beforeSave(pages[pageKey], json);
|
|
467
589
|
return dispatch(saveAndProcessPage(pageKey, page)).then(() => visitMeta);
|
|
468
590
|
}).catch((e) => handleFetchErr(e, fetchArgs, dispatch));
|
|
469
591
|
};
|
|
470
592
|
};
|
|
471
|
-
function calculateNavAction(meta, rsp, isGet, pageKey, currentPageKey, revisit) {
|
|
593
|
+
function calculateNavAction(meta, rsp, json, isGet, pageKey, currentPageKey, revisit) {
|
|
472
594
|
let navigationAction = "push";
|
|
595
|
+
if (json.action === "handleStreamResponse") {
|
|
596
|
+
return "none";
|
|
597
|
+
}
|
|
473
598
|
if (!rsp.redirected && !isGet) {
|
|
474
599
|
navigationAction = "replace";
|
|
475
600
|
}
|
|
@@ -498,6 +623,311 @@ function calculatePageKey(rsp, isGet, currentPageKey) {
|
|
|
498
623
|
return pageKey;
|
|
499
624
|
}
|
|
500
625
|
|
|
626
|
+
// lib/action_creators/stream.ts
|
|
627
|
+
var streamPrepend = (fragments, data, options = {}) => {
|
|
628
|
+
return (dispatch) => {
|
|
629
|
+
if (options.saveAs) {
|
|
630
|
+
const { saveAs } = options;
|
|
631
|
+
dispatch(
|
|
632
|
+
saveFragment({
|
|
633
|
+
fragmentId: saveAs,
|
|
634
|
+
data
|
|
635
|
+
})
|
|
636
|
+
);
|
|
637
|
+
fragments.forEach((fragmentId) => {
|
|
638
|
+
dispatch(
|
|
639
|
+
prependToFragment({
|
|
640
|
+
fragmentId,
|
|
641
|
+
data: {
|
|
642
|
+
__id: saveAs
|
|
643
|
+
}
|
|
644
|
+
})
|
|
645
|
+
);
|
|
646
|
+
});
|
|
647
|
+
} else {
|
|
648
|
+
fragments.forEach((fragmentId) => {
|
|
649
|
+
dispatch(
|
|
650
|
+
prependToFragment({
|
|
651
|
+
fragmentId,
|
|
652
|
+
data
|
|
653
|
+
})
|
|
654
|
+
);
|
|
655
|
+
});
|
|
656
|
+
}
|
|
657
|
+
};
|
|
658
|
+
};
|
|
659
|
+
var streamAppend = (fragments, data, options = {}) => {
|
|
660
|
+
return (dispatch) => {
|
|
661
|
+
if (options.saveAs) {
|
|
662
|
+
const { saveAs } = options;
|
|
663
|
+
dispatch(
|
|
664
|
+
saveFragment({
|
|
665
|
+
fragmentId: saveAs,
|
|
666
|
+
data
|
|
667
|
+
})
|
|
668
|
+
);
|
|
669
|
+
fragments.forEach((fragmentId) => {
|
|
670
|
+
dispatch(
|
|
671
|
+
appendToFragment({
|
|
672
|
+
fragmentId,
|
|
673
|
+
data: {
|
|
674
|
+
__id: saveAs
|
|
675
|
+
}
|
|
676
|
+
})
|
|
677
|
+
);
|
|
678
|
+
});
|
|
679
|
+
} else {
|
|
680
|
+
fragments.forEach((fragmentId) => {
|
|
681
|
+
dispatch(
|
|
682
|
+
appendToFragment({
|
|
683
|
+
fragmentId,
|
|
684
|
+
data
|
|
685
|
+
})
|
|
686
|
+
);
|
|
687
|
+
});
|
|
688
|
+
}
|
|
689
|
+
};
|
|
690
|
+
};
|
|
691
|
+
var streamSave = (fragment, data) => {
|
|
692
|
+
return (dispatch) => {
|
|
693
|
+
dispatch(
|
|
694
|
+
saveFragment({
|
|
695
|
+
fragmentId: fragment,
|
|
696
|
+
data
|
|
697
|
+
})
|
|
698
|
+
);
|
|
699
|
+
};
|
|
700
|
+
};
|
|
701
|
+
var handleStreamResponse = (response) => {
|
|
702
|
+
return (dispatch) => {
|
|
703
|
+
let nextResponse = response;
|
|
704
|
+
nextResponse.fragments.reverse().forEach((fragment) => {
|
|
705
|
+
const { id, path } = fragment;
|
|
706
|
+
const node = getIn(nextResponse, path);
|
|
707
|
+
nextResponse = setIn(nextResponse, path, { __id: id });
|
|
708
|
+
dispatch(
|
|
709
|
+
saveFragment({
|
|
710
|
+
fragmentId: id,
|
|
711
|
+
data: node
|
|
712
|
+
})
|
|
713
|
+
);
|
|
714
|
+
});
|
|
715
|
+
nextResponse.data.forEach((message) => {
|
|
716
|
+
if (message.handler === "append") {
|
|
717
|
+
dispatch(
|
|
718
|
+
streamAppend(message.fragmentIds, message.data, message.options)
|
|
719
|
+
);
|
|
720
|
+
}
|
|
721
|
+
if (message.handler === "prepend") {
|
|
722
|
+
dispatch(
|
|
723
|
+
streamPrepend(message.fragmentIds, message.data, message.options)
|
|
724
|
+
);
|
|
725
|
+
}
|
|
726
|
+
if (message.handler === "save") {
|
|
727
|
+
dispatch(streamSave(message.fragmentIds[0], message.data));
|
|
728
|
+
}
|
|
729
|
+
});
|
|
730
|
+
};
|
|
731
|
+
};
|
|
732
|
+
|
|
733
|
+
// lib/utils/proxy.ts
|
|
734
|
+
var ORIGINAL_TARGET = Symbol("@@originalTarget");
|
|
735
|
+
var ARRAY_GETTER_METHODS = /* @__PURE__ */ new Set([
|
|
736
|
+
Symbol.iterator,
|
|
737
|
+
"at",
|
|
738
|
+
"concat",
|
|
739
|
+
"entries",
|
|
740
|
+
"every",
|
|
741
|
+
"filter",
|
|
742
|
+
"find",
|
|
743
|
+
"findIndex",
|
|
744
|
+
"flat",
|
|
745
|
+
"flatMap",
|
|
746
|
+
"forEach",
|
|
747
|
+
"includes",
|
|
748
|
+
"indexOf",
|
|
749
|
+
"join",
|
|
750
|
+
"keys",
|
|
751
|
+
"lastIndexOf",
|
|
752
|
+
"map",
|
|
753
|
+
"reduce",
|
|
754
|
+
"reduceRight",
|
|
755
|
+
"slice",
|
|
756
|
+
"some",
|
|
757
|
+
"toString",
|
|
758
|
+
"values"
|
|
759
|
+
]);
|
|
760
|
+
var ARRAY_SETTER_METHODS = /* @__PURE__ */ new Set([
|
|
761
|
+
"copyWithin",
|
|
762
|
+
"fill",
|
|
763
|
+
"pop",
|
|
764
|
+
"push",
|
|
765
|
+
"reverse",
|
|
766
|
+
"shift",
|
|
767
|
+
"sort",
|
|
768
|
+
"splice",
|
|
769
|
+
"unshift"
|
|
770
|
+
]);
|
|
771
|
+
function isArraySetter(prop) {
|
|
772
|
+
return ARRAY_SETTER_METHODS.has(prop);
|
|
773
|
+
}
|
|
774
|
+
function isArrayGetter(prop) {
|
|
775
|
+
return ARRAY_GETTER_METHODS.has(prop);
|
|
776
|
+
}
|
|
777
|
+
function convertToInt(prop) {
|
|
778
|
+
if (typeof prop === "symbol") return null;
|
|
779
|
+
const num = Number(prop);
|
|
780
|
+
return Number.isInteger(num) ? num : null;
|
|
781
|
+
}
|
|
782
|
+
function isFragmentReference(value) {
|
|
783
|
+
return !!value && typeof value === "object" && "__id" in value && typeof value.__id === "string";
|
|
784
|
+
}
|
|
785
|
+
function createArrayProxy(arrayData, fragments, dependencies, proxyCache) {
|
|
786
|
+
if (proxyCache && proxyCache.has(arrayData)) {
|
|
787
|
+
return proxyCache.get(arrayData);
|
|
788
|
+
}
|
|
789
|
+
const proxy = new Proxy(arrayData, {
|
|
790
|
+
get(target, prop) {
|
|
791
|
+
if (prop === ORIGINAL_TARGET) {
|
|
792
|
+
return target;
|
|
793
|
+
}
|
|
794
|
+
if (isArrayGetter(prop)) {
|
|
795
|
+
const method = target[prop];
|
|
796
|
+
if (typeof method === "function") {
|
|
797
|
+
return function(...args) {
|
|
798
|
+
return Reflect.apply(method, proxy, args);
|
|
799
|
+
};
|
|
800
|
+
}
|
|
801
|
+
return method;
|
|
802
|
+
}
|
|
803
|
+
if (isArraySetter(prop)) {
|
|
804
|
+
throw new Error(
|
|
805
|
+
`Cannot mutate proxy array. Use Redux actions to update state.`
|
|
806
|
+
);
|
|
807
|
+
}
|
|
808
|
+
const index = convertToInt(prop);
|
|
809
|
+
if (index !== null && index >= 0 && index < target.length) {
|
|
810
|
+
const item = target[index];
|
|
811
|
+
if (isFragmentReference(item)) {
|
|
812
|
+
dependencies.add(item.__id);
|
|
813
|
+
const fragmentData = fragments.current[item.__id];
|
|
814
|
+
if (!fragmentData) {
|
|
815
|
+
throw new Error(`Fragment with id "${item.__id}" not found`);
|
|
816
|
+
}
|
|
817
|
+
return createProxy(fragmentData, fragments, dependencies, proxyCache);
|
|
818
|
+
}
|
|
819
|
+
if (typeof item === "object" && item !== null) {
|
|
820
|
+
if ("$$typeof" in item) {
|
|
821
|
+
return item;
|
|
822
|
+
} else {
|
|
823
|
+
return createProxy(
|
|
824
|
+
item,
|
|
825
|
+
fragments,
|
|
826
|
+
dependencies,
|
|
827
|
+
proxyCache
|
|
828
|
+
);
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
return item;
|
|
832
|
+
}
|
|
833
|
+
return Reflect.get(target, prop);
|
|
834
|
+
},
|
|
835
|
+
has(target, prop) {
|
|
836
|
+
if (prop === ORIGINAL_TARGET) {
|
|
837
|
+
return true;
|
|
838
|
+
}
|
|
839
|
+
return Reflect.has(target, prop);
|
|
840
|
+
},
|
|
841
|
+
set() {
|
|
842
|
+
throw new Error(
|
|
843
|
+
"Cannot mutate proxy array. Use Redux actions to update state."
|
|
844
|
+
);
|
|
845
|
+
},
|
|
846
|
+
deleteProperty() {
|
|
847
|
+
throw new Error(
|
|
848
|
+
"Cannot delete properties on proxy array. Use Redux actions to update state."
|
|
849
|
+
);
|
|
850
|
+
},
|
|
851
|
+
defineProperty() {
|
|
852
|
+
throw new Error(
|
|
853
|
+
"Cannot define properties on proxy array. Use Redux actions to update state."
|
|
854
|
+
);
|
|
855
|
+
}
|
|
856
|
+
});
|
|
857
|
+
if (proxyCache) {
|
|
858
|
+
proxyCache.set(arrayData, proxy);
|
|
859
|
+
}
|
|
860
|
+
return proxy;
|
|
861
|
+
}
|
|
862
|
+
function createObjectProxy(objectData, fragments, dependencies, proxyCache) {
|
|
863
|
+
if (proxyCache && proxyCache.has(objectData)) {
|
|
864
|
+
return proxyCache.get(objectData);
|
|
865
|
+
}
|
|
866
|
+
const proxy = new Proxy(objectData, {
|
|
867
|
+
get(target, prop) {
|
|
868
|
+
if (prop === ORIGINAL_TARGET) {
|
|
869
|
+
return target;
|
|
870
|
+
}
|
|
871
|
+
const value = target[prop];
|
|
872
|
+
if (isFragmentReference(value)) {
|
|
873
|
+
dependencies.add(value.__id);
|
|
874
|
+
const fragmentData = fragments.current[value.__id];
|
|
875
|
+
if (!fragmentData) {
|
|
876
|
+
throw new Error(`Fragment with id "${value.__id}" not found`);
|
|
877
|
+
}
|
|
878
|
+
return createProxy(fragmentData, fragments, dependencies, proxyCache);
|
|
879
|
+
}
|
|
880
|
+
if (typeof value === "object" && value !== null) {
|
|
881
|
+
if ("$$typeof" in value) {
|
|
882
|
+
return value;
|
|
883
|
+
} else if (Array.isArray(value)) {
|
|
884
|
+
return createArrayProxy(value, fragments, dependencies, proxyCache);
|
|
885
|
+
} else {
|
|
886
|
+
return createObjectProxy(value, fragments, dependencies, proxyCache);
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
return value;
|
|
890
|
+
},
|
|
891
|
+
has(target, prop) {
|
|
892
|
+
if (prop === ORIGINAL_TARGET) {
|
|
893
|
+
return true;
|
|
894
|
+
}
|
|
895
|
+
return Reflect.has(target, prop);
|
|
896
|
+
},
|
|
897
|
+
set() {
|
|
898
|
+
throw new Error(
|
|
899
|
+
"Cannot mutate proxy object. Use Redux actions to update state."
|
|
900
|
+
);
|
|
901
|
+
},
|
|
902
|
+
deleteProperty() {
|
|
903
|
+
throw new Error(
|
|
904
|
+
"Cannot delete properties on proxy object. Use Redux actions to update state."
|
|
905
|
+
);
|
|
906
|
+
},
|
|
907
|
+
defineProperty() {
|
|
908
|
+
throw new Error(
|
|
909
|
+
"Cannot define properties on proxy object. Use Redux actions to update state."
|
|
910
|
+
);
|
|
911
|
+
}
|
|
912
|
+
});
|
|
913
|
+
if (proxyCache) {
|
|
914
|
+
proxyCache.set(objectData, proxy);
|
|
915
|
+
}
|
|
916
|
+
return proxy;
|
|
917
|
+
}
|
|
918
|
+
function createProxy(content, fragments, dependencies, proxyCache) {
|
|
919
|
+
if (!content || typeof content !== "object") {
|
|
920
|
+
return content;
|
|
921
|
+
}
|
|
922
|
+
if ("$$typeof" in content) {
|
|
923
|
+
return content;
|
|
924
|
+
}
|
|
925
|
+
if (Array.isArray(content)) {
|
|
926
|
+
return createArrayProxy(content, fragments, dependencies, proxyCache);
|
|
927
|
+
}
|
|
928
|
+
return createObjectProxy(content, fragments, dependencies, proxyCache);
|
|
929
|
+
}
|
|
930
|
+
|
|
501
931
|
// lib/action_creators/index.ts
|
|
502
932
|
function fetchDeferments(pageKey, defers = []) {
|
|
503
933
|
pageKey = urlToPageKey(pageKey);
|
|
@@ -531,58 +961,64 @@ function fetchDeferments(pageKey, defers = []) {
|
|
|
531
961
|
return Promise.all(fetches);
|
|
532
962
|
};
|
|
533
963
|
}
|
|
964
|
+
function addPlaceholdersToDeferredNodes(existingPage, page) {
|
|
965
|
+
const { defers = [] } = existingPage;
|
|
966
|
+
const prevDefers = defers.map(({ path }) => {
|
|
967
|
+
const node = getIn(existingPage, path);
|
|
968
|
+
const copy = JSON.stringify(node);
|
|
969
|
+
return [path, JSON.parse(copy)];
|
|
970
|
+
});
|
|
971
|
+
return prevDefers.reduce((memo, [path, node]) => {
|
|
972
|
+
return setIn(page, path, node);
|
|
973
|
+
}, page);
|
|
974
|
+
}
|
|
534
975
|
function saveAndProcessPage(pageKey, page) {
|
|
535
976
|
return (dispatch, getState) => {
|
|
536
977
|
pageKey = urlToPageKey(pageKey);
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
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);
|
|
978
|
+
let nextPage = page;
|
|
979
|
+
const state = getState();
|
|
980
|
+
if (page.action === "savePage" && state.pages[pageKey]) {
|
|
981
|
+
const existingPage = createProxy(
|
|
982
|
+
state.pages[pageKey],
|
|
983
|
+
{ current: state.fragments },
|
|
984
|
+
/* @__PURE__ */ new Set(),
|
|
985
|
+
/* @__PURE__ */ new WeakMap()
|
|
986
|
+
);
|
|
987
|
+
nextPage = JSON.parse(
|
|
988
|
+
JSON.stringify(addPlaceholdersToDeferredNodes(existingPage, nextPage))
|
|
989
|
+
);
|
|
990
|
+
}
|
|
991
|
+
page.fragments.reverse().forEach((fragment) => {
|
|
992
|
+
const { id, path } = fragment;
|
|
993
|
+
const node = getIn(nextPage, path);
|
|
994
|
+
nextPage = setIn(page, path, { __id: id });
|
|
995
|
+
dispatch(
|
|
996
|
+
saveFragment({
|
|
997
|
+
fragmentId: id,
|
|
998
|
+
data: node
|
|
999
|
+
})
|
|
1000
|
+
);
|
|
1001
|
+
});
|
|
1002
|
+
if (nextPage.action === "graft") {
|
|
1003
|
+
if (typeof nextPage.fragmentContext === "string") {
|
|
573
1004
|
dispatch(
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
value: currentFragment,
|
|
578
|
-
path
|
|
1005
|
+
handleFragmentGraft({
|
|
1006
|
+
fragmentId: nextPage.fragmentContext,
|
|
1007
|
+
response: nextPage
|
|
579
1008
|
})
|
|
580
1009
|
);
|
|
581
|
-
}
|
|
1010
|
+
} else {
|
|
1011
|
+
dispatch(handleGraft({ pageKey, page: nextPage }));
|
|
1012
|
+
}
|
|
1013
|
+
} else if (nextPage.action === "handleStreamResponse") {
|
|
1014
|
+
dispatch(handleStreamResponse(nextPage));
|
|
1015
|
+
return Promise.resolve();
|
|
1016
|
+
} else {
|
|
1017
|
+
dispatch(saveResponse({ pageKey, page: nextPage }));
|
|
582
1018
|
}
|
|
583
1019
|
const hasFetch = typeof fetch != "undefined";
|
|
584
1020
|
if (hasFetch) {
|
|
585
|
-
return dispatch(fetchDeferments(pageKey, defers)).then(
|
|
1021
|
+
return dispatch(fetchDeferments(pageKey, nextPage.defers)).then(
|
|
586
1022
|
() => Promise.resolve()
|
|
587
1023
|
);
|
|
588
1024
|
} else {
|