@inertiajs/core 2.2.18 → 2.2.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.esm.js CHANGED
@@ -38,7 +38,8 @@ var config = new Config({
38
38
  future: {
39
39
  preserveEqualProps: false,
40
40
  useDataInertiaHeadAttribute: false,
41
- useDialogForErrorModal: false
41
+ useDialogForErrorModal: false,
42
+ useScriptElementForInitialPage: false
42
43
  },
43
44
  prefetch: {
44
45
  cacheFor: 3e4,
@@ -97,7 +98,7 @@ var firePrefetchingEvent = (visit) => {
97
98
  };
98
99
 
99
100
  // src/history.ts
100
- import { cloneDeep, isEqual } from "lodash-es";
101
+ import { cloneDeep as cloneDeep2, isEqual } from "lodash-es";
101
102
 
102
103
  // src/sessionStorage.ts
103
104
  var SessionStorage = class {
@@ -268,6 +269,300 @@ var getKeyFromSessionStorage = async () => {
268
269
  return key;
269
270
  };
270
271
 
272
+ // src/prefetched.ts
273
+ import { cloneDeep } from "lodash-es";
274
+
275
+ // src/objectUtils.ts
276
+ var objectsAreEqual = (obj1, obj2, excludeKeys) => {
277
+ if (obj1 === obj2) {
278
+ return true;
279
+ }
280
+ for (const key in obj1) {
281
+ if (excludeKeys.includes(key)) {
282
+ continue;
283
+ }
284
+ if (obj1[key] === obj2[key]) {
285
+ continue;
286
+ }
287
+ if (!compareValues(obj1[key], obj2[key])) {
288
+ return false;
289
+ }
290
+ }
291
+ for (const key in obj2) {
292
+ if (excludeKeys.includes(key)) {
293
+ continue;
294
+ }
295
+ if (!(key in obj1)) {
296
+ return false;
297
+ }
298
+ }
299
+ return true;
300
+ };
301
+ var compareValues = (value1, value2) => {
302
+ switch (typeof value1) {
303
+ case "object":
304
+ return objectsAreEqual(value1, value2, []);
305
+ case "function":
306
+ return value1.toString() === value2.toString();
307
+ default:
308
+ return value1 === value2;
309
+ }
310
+ };
311
+
312
+ // src/time.ts
313
+ var conversionMap = {
314
+ ms: 1,
315
+ s: 1e3,
316
+ m: 1e3 * 60,
317
+ h: 1e3 * 60 * 60,
318
+ d: 1e3 * 60 * 60 * 24
319
+ };
320
+ var timeToMs = (time) => {
321
+ if (typeof time === "number") {
322
+ return time;
323
+ }
324
+ for (const [unit, conversion] of Object.entries(conversionMap)) {
325
+ if (time.endsWith(unit)) {
326
+ return parseFloat(time) * conversion;
327
+ }
328
+ }
329
+ return parseInt(time);
330
+ };
331
+
332
+ // src/prefetched.ts
333
+ var PrefetchedRequests = class {
334
+ constructor() {
335
+ this.cached = [];
336
+ this.inFlightRequests = [];
337
+ this.removalTimers = [];
338
+ this.currentUseId = null;
339
+ }
340
+ add(params, sendFunc, { cacheFor, cacheTags }) {
341
+ const inFlight = this.findInFlight(params);
342
+ if (inFlight) {
343
+ return Promise.resolve();
344
+ }
345
+ const existing = this.findCached(params);
346
+ if (!params.fresh && existing && existing.staleTimestamp > Date.now()) {
347
+ return Promise.resolve();
348
+ }
349
+ const [stale, prefetchExpiresIn] = this.extractStaleValues(cacheFor);
350
+ const promise = new Promise((resolve, reject) => {
351
+ sendFunc({
352
+ ...params,
353
+ onCancel: () => {
354
+ this.remove(params);
355
+ params.onCancel();
356
+ reject();
357
+ },
358
+ onError: (error) => {
359
+ this.remove(params);
360
+ params.onError(error);
361
+ reject();
362
+ },
363
+ onPrefetching(visitParams) {
364
+ params.onPrefetching(visitParams);
365
+ },
366
+ onPrefetched(response, visit) {
367
+ params.onPrefetched(response, visit);
368
+ },
369
+ onPrefetchResponse(response) {
370
+ resolve(response);
371
+ },
372
+ onPrefetchError(error) {
373
+ prefetchedRequests.removeFromInFlight(params);
374
+ reject(error);
375
+ }
376
+ });
377
+ }).then((response) => {
378
+ this.remove(params);
379
+ const pageResponse = response.getPageResponse();
380
+ page.mergeOncePropsIntoResponse(pageResponse);
381
+ this.cached.push({
382
+ params: { ...params },
383
+ staleTimestamp: Date.now() + stale,
384
+ expiresAt: Date.now() + prefetchExpiresIn,
385
+ response: promise,
386
+ singleUse: prefetchExpiresIn === 0,
387
+ timestamp: Date.now(),
388
+ inFlight: false,
389
+ tags: Array.isArray(cacheTags) ? cacheTags : [cacheTags]
390
+ });
391
+ const oncePropExpiresIn = this.getShortestOncePropTtl(pageResponse);
392
+ this.scheduleForRemoval(
393
+ params,
394
+ oncePropExpiresIn ? Math.min(prefetchExpiresIn, oncePropExpiresIn) : prefetchExpiresIn
395
+ );
396
+ this.removeFromInFlight(params);
397
+ response.handlePrefetch();
398
+ return response;
399
+ });
400
+ this.inFlightRequests.push({
401
+ params: { ...params },
402
+ response: promise,
403
+ staleTimestamp: null,
404
+ inFlight: true
405
+ });
406
+ return promise;
407
+ }
408
+ removeAll() {
409
+ this.cached = [];
410
+ this.removalTimers.forEach((removalTimer) => {
411
+ clearTimeout(removalTimer.timer);
412
+ });
413
+ this.removalTimers = [];
414
+ }
415
+ removeByTags(tags) {
416
+ this.cached = this.cached.filter((prefetched) => {
417
+ return !prefetched.tags.some((tag) => tags.includes(tag));
418
+ });
419
+ }
420
+ remove(params) {
421
+ this.cached = this.cached.filter((prefetched) => {
422
+ return !this.paramsAreEqual(prefetched.params, params);
423
+ });
424
+ this.clearTimer(params);
425
+ }
426
+ removeFromInFlight(params) {
427
+ this.inFlightRequests = this.inFlightRequests.filter((prefetching) => {
428
+ return !this.paramsAreEqual(prefetching.params, params);
429
+ });
430
+ }
431
+ extractStaleValues(cacheFor) {
432
+ const [stale, expires] = this.cacheForToStaleAndExpires(cacheFor);
433
+ return [timeToMs(stale), timeToMs(expires)];
434
+ }
435
+ cacheForToStaleAndExpires(cacheFor) {
436
+ if (!Array.isArray(cacheFor)) {
437
+ return [cacheFor, cacheFor];
438
+ }
439
+ switch (cacheFor.length) {
440
+ case 0:
441
+ return [0, 0];
442
+ case 1:
443
+ return [cacheFor[0], cacheFor[0]];
444
+ default:
445
+ return [cacheFor[0], cacheFor[1]];
446
+ }
447
+ }
448
+ clearTimer(params) {
449
+ const timer = this.removalTimers.find((removalTimer) => {
450
+ return this.paramsAreEqual(removalTimer.params, params);
451
+ });
452
+ if (timer) {
453
+ clearTimeout(timer.timer);
454
+ this.removalTimers = this.removalTimers.filter((removalTimer) => removalTimer !== timer);
455
+ }
456
+ }
457
+ scheduleForRemoval(params, expiresIn) {
458
+ if (typeof window === "undefined") {
459
+ return;
460
+ }
461
+ this.clearTimer(params);
462
+ if (expiresIn > 0) {
463
+ const timer = window.setTimeout(() => this.remove(params), expiresIn);
464
+ this.removalTimers.push({
465
+ params,
466
+ timer
467
+ });
468
+ }
469
+ }
470
+ get(params) {
471
+ return this.findCached(params) || this.findInFlight(params);
472
+ }
473
+ use(prefetched, params) {
474
+ const id = `${params.url.pathname}-${Date.now()}-${Math.random().toString(36).substring(7)}`;
475
+ this.currentUseId = id;
476
+ return prefetched.response.then((response) => {
477
+ if (this.currentUseId !== id) {
478
+ return;
479
+ }
480
+ response.mergeParams({ ...params, onPrefetched: () => {
481
+ } });
482
+ this.removeSingleUseItems(params);
483
+ return response.handle();
484
+ });
485
+ }
486
+ removeSingleUseItems(params) {
487
+ this.cached = this.cached.filter((prefetched) => {
488
+ if (!this.paramsAreEqual(prefetched.params, params)) {
489
+ return true;
490
+ }
491
+ return !prefetched.singleUse;
492
+ });
493
+ }
494
+ findCached(params) {
495
+ return this.cached.find((prefetched) => {
496
+ return this.paramsAreEqual(prefetched.params, params);
497
+ }) || null;
498
+ }
499
+ findInFlight(params) {
500
+ return this.inFlightRequests.find((prefetched) => {
501
+ return this.paramsAreEqual(prefetched.params, params);
502
+ }) || null;
503
+ }
504
+ withoutPurposePrefetchHeader(params) {
505
+ const newParams = cloneDeep(params);
506
+ if (newParams.headers["Purpose"] === "prefetch") {
507
+ delete newParams.headers["Purpose"];
508
+ }
509
+ return newParams;
510
+ }
511
+ paramsAreEqual(params1, params2) {
512
+ return objectsAreEqual(
513
+ this.withoutPurposePrefetchHeader(params1),
514
+ this.withoutPurposePrefetchHeader(params2),
515
+ [
516
+ "showProgress",
517
+ "replace",
518
+ "prefetch",
519
+ "preserveScroll",
520
+ "preserveState",
521
+ "onBefore",
522
+ "onBeforeUpdate",
523
+ "onStart",
524
+ "onProgress",
525
+ "onFinish",
526
+ "onCancel",
527
+ "onSuccess",
528
+ "onError",
529
+ "onPrefetched",
530
+ "onCancelToken",
531
+ "onPrefetching",
532
+ "async",
533
+ "viewTransition"
534
+ ]
535
+ );
536
+ }
537
+ updateCachedOncePropsFromCurrentPage() {
538
+ this.cached.forEach((prefetched) => {
539
+ prefetched.response.then((response) => {
540
+ const pageResponse = response.getPageResponse();
541
+ page.mergeOncePropsIntoResponse(pageResponse, { force: true });
542
+ const oncePropExpiresIn = this.getShortestOncePropTtl(pageResponse);
543
+ if (oncePropExpiresIn === null) {
544
+ return;
545
+ }
546
+ const prefetchExpiresIn = prefetched.expiresAt - Date.now();
547
+ const expiresIn = Math.min(prefetchExpiresIn, oncePropExpiresIn);
548
+ if (expiresIn > 0) {
549
+ this.scheduleForRemoval(prefetched.params, expiresIn);
550
+ } else {
551
+ this.remove(prefetched.params);
552
+ }
553
+ });
554
+ });
555
+ }
556
+ getShortestOncePropTtl(page2) {
557
+ const expiryTimestamps = Object.values(page2.onceProps ?? {}).map((onceProp) => onceProp.expiresAt).filter((expiresAt) => !!expiresAt);
558
+ if (expiryTimestamps.length === 0) {
559
+ return null;
560
+ }
561
+ return Math.min(...expiryTimestamps) - Date.now();
562
+ }
563
+ };
564
+ var prefetchedRequests = new PrefetchedRequests();
565
+
271
566
  // src/scroll.ts
272
567
  var Scroll = class {
273
568
  static save() {
@@ -295,6 +590,10 @@ var Scroll = class {
295
590
  }
296
591
  });
297
592
  this.save();
593
+ this.scrollToAnchor();
594
+ }
595
+ static scrollToAnchor() {
596
+ const anchorHash = typeof window !== "undefined" ? window.location.hash : null;
298
597
  if (anchorHash) {
299
598
  setTimeout(() => {
300
599
  const anchorElement = document.getElementById(anchorHash.slice(1));
@@ -522,6 +821,9 @@ var CurrentPage = class {
522
821
  }
523
822
  this.page = page2;
524
823
  this.cleared = false;
824
+ if (this.hasOnceProps()) {
825
+ prefetchedRequests.updateCachedOncePropsFromCurrentPage();
826
+ }
525
827
  if (isNewComponent) {
526
828
  this.fireEventsFor("newComponent");
527
829
  }
@@ -570,6 +872,9 @@ var CurrentPage = class {
570
872
  get() {
571
873
  return this.page;
572
874
  }
875
+ hasOnceProps() {
876
+ return Object.keys(this.page.onceProps ?? {}).length > 0;
877
+ }
573
878
  merge(data) {
574
879
  this.page = { ...this.page, ...data };
575
880
  }
@@ -612,6 +917,18 @@ var CurrentPage = class {
612
917
  fireEventsFor(event) {
613
918
  this.listeners.filter((listener) => listener.event === event).forEach((listener) => listener.callback());
614
919
  }
920
+ mergeOncePropsIntoResponse(response, { force = false } = {}) {
921
+ Object.entries(response.onceProps ?? {}).forEach(([key, onceProp]) => {
922
+ const existingOnceProp = this.page.onceProps?.[key];
923
+ if (existingOnceProp === void 0) {
924
+ return;
925
+ }
926
+ if (force || response.props[onceProp.prop] === void 0) {
927
+ response.props[onceProp.prop] = this.page.props[existingOnceProp.prop];
928
+ response.onceProps[key].expiresAt = existingOnceProp.expiresAt;
929
+ }
930
+ });
931
+ }
615
932
  };
616
933
  var page = new CurrentPage();
617
934
 
@@ -695,7 +1012,7 @@ var History = class {
695
1012
  } catch {
696
1013
  return {
697
1014
  ...page2,
698
- props: cloneDeep(page2.props)
1015
+ props: cloneDeep2(page2.props)
699
1016
  };
700
1017
  }
701
1018
  }
@@ -798,548 +1115,289 @@ var History = class {
798
1115
  },
799
1116
  "",
800
1117
  url
801
- )
802
- );
803
- }
804
- doPushState(data, url) {
805
- return Promise.resolve().then(() => window.history.pushState(data, "", url));
806
- }
807
- getState(key, defaultValue) {
808
- return this.current?.[key] ?? defaultValue;
809
- }
810
- deleteState(key) {
811
- if (this.current[key] !== void 0) {
812
- delete this.current[key];
813
- this.replaceState(this.current);
814
- }
815
- }
816
- clearInitialState(key) {
817
- if (this.initialState && this.initialState[key] !== void 0) {
818
- delete this.initialState[key];
819
- }
820
- }
821
- hasAnyState() {
822
- return !!this.getAllState();
823
- }
824
- clear() {
825
- SessionStorage.remove(historySessionStorageKeys.key);
826
- SessionStorage.remove(historySessionStorageKeys.iv);
827
- }
828
- setCurrent(page2) {
829
- this.current = page2;
830
- }
831
- isValidState(state) {
832
- return !!state.page;
833
- }
834
- getAllState() {
835
- return this.current;
836
- }
837
- };
838
- if (typeof window !== "undefined" && window.history.scrollRestoration) {
839
- window.history.scrollRestoration = "manual";
840
- }
841
- var history = new History();
842
-
843
- // src/eventHandler.ts
844
- var EventHandler = class {
845
- constructor() {
846
- this.internalListeners = [];
847
- }
848
- init() {
849
- if (typeof window !== "undefined") {
850
- window.addEventListener("popstate", this.handlePopstateEvent.bind(this));
851
- window.addEventListener("scroll", debounce(Scroll.onWindowScroll.bind(Scroll), 100), true);
852
- }
853
- if (typeof document !== "undefined") {
854
- document.addEventListener("scroll", debounce(Scroll.onScroll.bind(Scroll), 100), true);
855
- }
856
- }
857
- onGlobalEvent(type, callback) {
858
- const listener = ((event) => {
859
- const response = callback(event);
860
- if (event.cancelable && !event.defaultPrevented && response === false) {
861
- event.preventDefault();
862
- }
863
- });
864
- return this.registerListener(`inertia:${type}`, listener);
865
- }
866
- on(event, callback) {
867
- this.internalListeners.push({ event, listener: callback });
868
- return () => {
869
- this.internalListeners = this.internalListeners.filter((listener) => listener.listener !== callback);
870
- };
871
- }
872
- onMissingHistoryItem() {
873
- page.clear();
874
- this.fireInternalEvent("missingHistoryItem");
875
- }
876
- fireInternalEvent(event, ...args) {
877
- this.internalListeners.filter((listener) => listener.event === event).forEach((listener) => listener.listener(...args));
878
- }
879
- registerListener(type, listener) {
880
- document.addEventListener(type, listener);
881
- return () => document.removeEventListener(type, listener);
882
- }
883
- handlePopstateEvent(event) {
884
- const state = event.state || null;
885
- if (state === null) {
886
- const url = hrefToUrl(page.get().url);
887
- url.hash = window.location.hash;
888
- history.replaceState({ ...page.get(), url: url.href });
889
- Scroll.reset();
890
- return;
891
- }
892
- if (!history.isValidState(state)) {
893
- return this.onMissingHistoryItem();
894
- }
895
- history.decrypt(state.page).then((data) => {
896
- if (page.get().version !== data.version) {
897
- this.onMissingHistoryItem();
898
- return;
899
- }
900
- router.cancelAll();
901
- page.setQuietly(data, { preserveState: false }).then(() => {
902
- Scroll.restore(history.getScrollRegions());
903
- fireNavigateEvent(page.get());
904
- });
905
- }).catch(() => {
906
- this.onMissingHistoryItem();
907
- });
908
- }
909
- };
910
- var eventHandler = new EventHandler();
911
-
912
- // src/navigationType.ts
913
- var NavigationType = class {
914
- constructor() {
915
- this.type = this.resolveType();
916
- }
917
- resolveType() {
918
- if (typeof window === "undefined") {
919
- return "navigate";
920
- }
921
- if (window.performance && window.performance.getEntriesByType && window.performance.getEntriesByType("navigation").length > 0) {
922
- return window.performance.getEntriesByType("navigation")[0].type;
923
- }
924
- return "navigate";
925
- }
926
- get() {
927
- return this.type;
928
- }
929
- isBackForward() {
930
- return this.type === "back_forward";
931
- }
932
- isReload() {
933
- return this.type === "reload";
934
- }
935
- };
936
- var navigationType = new NavigationType();
937
-
938
- // src/initialVisit.ts
939
- var InitialVisit = class {
940
- static handle() {
941
- this.clearRememberedStateOnReload();
942
- const scenarios = [this.handleBackForward, this.handleLocation, this.handleDefault];
943
- scenarios.find((handler) => handler.bind(this)());
944
- }
945
- static clearRememberedStateOnReload() {
946
- if (navigationType.isReload()) {
947
- history.deleteState(history.rememberedState);
948
- history.clearInitialState(history.rememberedState);
949
- }
950
- }
951
- static handleBackForward() {
952
- if (!navigationType.isBackForward() || !history.hasAnyState()) {
953
- return false;
954
- }
955
- const scrollRegions = history.getScrollRegions();
956
- history.decrypt().then((data) => {
957
- page.set(data, { preserveScroll: true, preserveState: true }).then(() => {
958
- Scroll.restore(scrollRegions);
959
- fireNavigateEvent(page.get());
960
- });
961
- }).catch(() => {
962
- eventHandler.onMissingHistoryItem();
963
- });
964
- return true;
965
- }
966
- /**
967
- * @link https://inertiajs.com/redirects#external-redirects
968
- */
969
- static handleLocation() {
970
- if (!SessionStorage.exists(SessionStorage.locationVisitKey)) {
971
- return false;
972
- }
973
- const locationVisit = SessionStorage.get(SessionStorage.locationVisitKey) || {};
974
- SessionStorage.remove(SessionStorage.locationVisitKey);
975
- if (typeof window !== "undefined") {
976
- page.setUrlHash(window.location.hash);
977
- }
978
- history.decrypt(page.get()).then(() => {
979
- const rememberedState = history.getState(history.rememberedState, {});
980
- const scrollRegions = history.getScrollRegions();
981
- page.remember(rememberedState);
982
- page.set(page.get(), {
983
- preserveScroll: locationVisit.preserveScroll,
984
- preserveState: true
985
- }).then(() => {
986
- if (locationVisit.preserveScroll) {
987
- Scroll.restore(scrollRegions);
988
- }
989
- fireNavigateEvent(page.get());
990
- });
991
- }).catch(() => {
992
- eventHandler.onMissingHistoryItem();
993
- });
994
- return true;
995
- }
996
- static handleDefault() {
997
- if (typeof window !== "undefined") {
998
- page.setUrlHash(window.location.hash);
999
- }
1000
- page.set(page.get(), { preserveScroll: true, preserveState: true }).then(() => {
1001
- if (navigationType.isReload()) {
1002
- Scroll.restore(history.getScrollRegions());
1003
- }
1004
- fireNavigateEvent(page.get());
1005
- });
1006
- }
1007
- };
1008
-
1009
- // src/poll.ts
1010
- var Poll = class {
1011
- constructor(interval, cb, options) {
1012
- this.id = null;
1013
- this.throttle = false;
1014
- this.keepAlive = false;
1015
- this.cbCount = 0;
1016
- this.keepAlive = options.keepAlive ?? false;
1017
- this.cb = cb;
1018
- this.interval = interval;
1019
- if (options.autoStart ?? true) {
1020
- this.start();
1021
- }
1118
+ )
1119
+ );
1022
1120
  }
1023
- stop() {
1024
- if (this.id) {
1025
- clearInterval(this.id);
1026
- }
1121
+ doPushState(data, url) {
1122
+ return Promise.resolve().then(() => window.history.pushState(data, "", url));
1027
1123
  }
1028
- start() {
1029
- if (typeof window === "undefined") {
1030
- return;
1031
- }
1032
- this.stop();
1033
- this.id = window.setInterval(() => {
1034
- if (!this.throttle || this.cbCount % 10 === 0) {
1035
- this.cb();
1036
- }
1037
- if (this.throttle) {
1038
- this.cbCount++;
1039
- }
1040
- }, this.interval);
1124
+ getState(key, defaultValue) {
1125
+ return this.current?.[key] ?? defaultValue;
1041
1126
  }
1042
- isInBackground(hidden) {
1043
- this.throttle = this.keepAlive ? false : hidden;
1044
- if (this.throttle) {
1045
- this.cbCount = 0;
1127
+ deleteState(key) {
1128
+ if (this.current[key] !== void 0) {
1129
+ delete this.current[key];
1130
+ this.replaceState(this.current);
1046
1131
  }
1047
1132
  }
1048
- };
1049
-
1050
- // src/polls.ts
1051
- var Polls = class {
1052
- constructor() {
1053
- this.polls = [];
1054
- this.setupVisibilityListener();
1133
+ clearInitialState(key) {
1134
+ if (this.initialState && this.initialState[key] !== void 0) {
1135
+ delete this.initialState[key];
1136
+ }
1055
1137
  }
1056
- add(interval, cb, options) {
1057
- const poll = new Poll(interval, cb, options);
1058
- this.polls.push(poll);
1059
- return {
1060
- stop: () => poll.stop(),
1061
- start: () => poll.start()
1062
- };
1138
+ hasAnyState() {
1139
+ return !!this.getAllState();
1063
1140
  }
1064
1141
  clear() {
1065
- this.polls.forEach((poll) => poll.stop());
1066
- this.polls = [];
1142
+ SessionStorage.remove(historySessionStorageKeys.key);
1143
+ SessionStorage.remove(historySessionStorageKeys.iv);
1067
1144
  }
1068
- setupVisibilityListener() {
1069
- if (typeof document === "undefined") {
1070
- return;
1071
- }
1072
- document.addEventListener(
1073
- "visibilitychange",
1074
- () => {
1075
- this.polls.forEach((poll) => poll.isInBackground(document.hidden));
1076
- },
1077
- false
1078
- );
1145
+ setCurrent(page2) {
1146
+ this.current = page2;
1147
+ }
1148
+ isValidState(state) {
1149
+ return !!state.page;
1150
+ }
1151
+ getAllState() {
1152
+ return this.current;
1079
1153
  }
1080
1154
  };
1081
- var polls = new Polls();
1082
-
1083
- // src/prefetched.ts
1084
- import { cloneDeep as cloneDeep2 } from "lodash-es";
1155
+ if (typeof window !== "undefined" && window.history.scrollRestoration) {
1156
+ window.history.scrollRestoration = "manual";
1157
+ }
1158
+ var history = new History();
1085
1159
 
1086
- // src/objectUtils.ts
1087
- var objectsAreEqual = (obj1, obj2, excludeKeys) => {
1088
- if (obj1 === obj2) {
1089
- return true;
1160
+ // src/eventHandler.ts
1161
+ var EventHandler = class {
1162
+ constructor() {
1163
+ this.internalListeners = [];
1090
1164
  }
1091
- for (const key in obj1) {
1092
- if (excludeKeys.includes(key)) {
1093
- continue;
1094
- }
1095
- if (obj1[key] === obj2[key]) {
1096
- continue;
1165
+ init() {
1166
+ if (typeof window !== "undefined") {
1167
+ window.addEventListener("popstate", this.handlePopstateEvent.bind(this));
1168
+ window.addEventListener("scroll", debounce(Scroll.onWindowScroll.bind(Scroll), 100), true);
1097
1169
  }
1098
- if (!compareValues(obj1[key], obj2[key])) {
1099
- return false;
1170
+ if (typeof document !== "undefined") {
1171
+ document.addEventListener("scroll", debounce(Scroll.onScroll.bind(Scroll), 100), true);
1100
1172
  }
1101
1173
  }
1102
- for (const key in obj2) {
1103
- if (excludeKeys.includes(key)) {
1104
- continue;
1105
- }
1106
- if (!(key in obj1)) {
1107
- return false;
1108
- }
1174
+ onGlobalEvent(type, callback) {
1175
+ const listener = ((event) => {
1176
+ const response = callback(event);
1177
+ if (event.cancelable && !event.defaultPrevented && response === false) {
1178
+ event.preventDefault();
1179
+ }
1180
+ });
1181
+ return this.registerListener(`inertia:${type}`, listener);
1109
1182
  }
1110
- return true;
1111
- };
1112
- var compareValues = (value1, value2) => {
1113
- switch (typeof value1) {
1114
- case "object":
1115
- return objectsAreEqual(value1, value2, []);
1116
- case "function":
1117
- return value1.toString() === value2.toString();
1118
- default:
1119
- return value1 === value2;
1183
+ on(event, callback) {
1184
+ this.internalListeners.push({ event, listener: callback });
1185
+ return () => {
1186
+ this.internalListeners = this.internalListeners.filter((listener) => listener.listener !== callback);
1187
+ };
1120
1188
  }
1121
- };
1122
-
1123
- // src/time.ts
1124
- var conversionMap = {
1125
- ms: 1,
1126
- s: 1e3,
1127
- m: 1e3 * 60,
1128
- h: 1e3 * 60 * 60,
1129
- d: 1e3 * 60 * 60 * 24
1130
- };
1131
- var timeToMs = (time) => {
1132
- if (typeof time === "number") {
1133
- return time;
1189
+ onMissingHistoryItem() {
1190
+ page.clear();
1191
+ this.fireInternalEvent("missingHistoryItem");
1134
1192
  }
1135
- for (const [unit, conversion] of Object.entries(conversionMap)) {
1136
- if (time.endsWith(unit)) {
1137
- return parseFloat(time) * conversion;
1193
+ fireInternalEvent(event, ...args) {
1194
+ this.internalListeners.filter((listener) => listener.event === event).forEach((listener) => listener.listener(...args));
1195
+ }
1196
+ registerListener(type, listener) {
1197
+ document.addEventListener(type, listener);
1198
+ return () => document.removeEventListener(type, listener);
1199
+ }
1200
+ handlePopstateEvent(event) {
1201
+ const state = event.state || null;
1202
+ if (state === null) {
1203
+ const url = hrefToUrl(page.get().url);
1204
+ url.hash = window.location.hash;
1205
+ history.replaceState({ ...page.get(), url: url.href });
1206
+ Scroll.reset();
1207
+ return;
1208
+ }
1209
+ if (!history.isValidState(state)) {
1210
+ return this.onMissingHistoryItem();
1138
1211
  }
1212
+ history.decrypt(state.page).then((data) => {
1213
+ if (page.get().version !== data.version) {
1214
+ this.onMissingHistoryItem();
1215
+ return;
1216
+ }
1217
+ router.cancelAll();
1218
+ page.setQuietly(data, { preserveState: false }).then(() => {
1219
+ Scroll.restore(history.getScrollRegions());
1220
+ fireNavigateEvent(page.get());
1221
+ });
1222
+ }).catch(() => {
1223
+ this.onMissingHistoryItem();
1224
+ });
1139
1225
  }
1140
- return parseInt(time);
1141
1226
  };
1227
+ var eventHandler = new EventHandler();
1142
1228
 
1143
- // src/prefetched.ts
1144
- var PrefetchedRequests = class {
1229
+ // src/navigationType.ts
1230
+ var NavigationType = class {
1145
1231
  constructor() {
1146
- this.cached = [];
1147
- this.inFlightRequests = [];
1148
- this.removalTimers = [];
1149
- this.currentUseId = null;
1232
+ this.type = this.resolveType();
1150
1233
  }
1151
- add(params, sendFunc, { cacheFor, cacheTags }) {
1152
- const inFlight = this.findInFlight(params);
1153
- if (inFlight) {
1154
- return Promise.resolve();
1234
+ resolveType() {
1235
+ if (typeof window === "undefined") {
1236
+ return "navigate";
1155
1237
  }
1156
- const existing = this.findCached(params);
1157
- if (!params.fresh && existing && existing.staleTimestamp > Date.now()) {
1158
- return Promise.resolve();
1238
+ if (window.performance && window.performance.getEntriesByType && window.performance.getEntriesByType("navigation").length > 0) {
1239
+ return window.performance.getEntriesByType("navigation")[0].type;
1159
1240
  }
1160
- const [stale, expires] = this.extractStaleValues(cacheFor);
1161
- const promise = new Promise((resolve, reject) => {
1162
- sendFunc({
1163
- ...params,
1164
- onCancel: () => {
1165
- this.remove(params);
1166
- params.onCancel();
1167
- reject();
1168
- },
1169
- onError: (error) => {
1170
- this.remove(params);
1171
- params.onError(error);
1172
- reject();
1173
- },
1174
- onPrefetching(visitParams) {
1175
- params.onPrefetching(visitParams);
1176
- },
1177
- onPrefetched(response, visit) {
1178
- params.onPrefetched(response, visit);
1179
- },
1180
- onPrefetchResponse(response) {
1181
- resolve(response);
1182
- },
1183
- onPrefetchError(error) {
1184
- prefetchedRequests.removeFromInFlight(params);
1185
- reject(error);
1186
- }
1187
- });
1188
- }).then((response) => {
1189
- this.remove(params);
1190
- this.cached.push({
1191
- params: { ...params },
1192
- staleTimestamp: Date.now() + stale,
1193
- response: promise,
1194
- singleUse: expires === 0,
1195
- timestamp: Date.now(),
1196
- inFlight: false,
1197
- tags: Array.isArray(cacheTags) ? cacheTags : [cacheTags]
1198
- });
1199
- this.scheduleForRemoval(params, expires);
1200
- this.removeFromInFlight(params);
1201
- response.handlePrefetch();
1202
- return response;
1203
- });
1204
- this.inFlightRequests.push({
1205
- params: { ...params },
1206
- response: promise,
1207
- staleTimestamp: null,
1208
- inFlight: true
1209
- });
1210
- return promise;
1241
+ return "navigate";
1242
+ }
1243
+ get() {
1244
+ return this.type;
1211
1245
  }
1212
- removeAll() {
1213
- this.cached = [];
1214
- this.removalTimers.forEach((removalTimer) => {
1215
- clearTimeout(removalTimer.timer);
1216
- });
1217
- this.removalTimers = [];
1246
+ isBackForward() {
1247
+ return this.type === "back_forward";
1218
1248
  }
1219
- removeByTags(tags) {
1220
- this.cached = this.cached.filter((prefetched) => {
1221
- return !prefetched.tags.some((tag) => tags.includes(tag));
1222
- });
1249
+ isReload() {
1250
+ return this.type === "reload";
1223
1251
  }
1224
- remove(params) {
1225
- this.cached = this.cached.filter((prefetched) => {
1226
- return !this.paramsAreEqual(prefetched.params, params);
1227
- });
1228
- this.clearTimer(params);
1252
+ };
1253
+ var navigationType = new NavigationType();
1254
+
1255
+ // src/initialVisit.ts
1256
+ var InitialVisit = class {
1257
+ static handle() {
1258
+ this.clearRememberedStateOnReload();
1259
+ const scenarios = [this.handleBackForward, this.handleLocation, this.handleDefault];
1260
+ scenarios.find((handler) => handler.bind(this)());
1229
1261
  }
1230
- removeFromInFlight(params) {
1231
- this.inFlightRequests = this.inFlightRequests.filter((prefetching) => {
1232
- return !this.paramsAreEqual(prefetching.params, params);
1233
- });
1262
+ static clearRememberedStateOnReload() {
1263
+ if (navigationType.isReload()) {
1264
+ history.deleteState(history.rememberedState);
1265
+ history.clearInitialState(history.rememberedState);
1266
+ }
1234
1267
  }
1235
- extractStaleValues(cacheFor) {
1236
- const [stale, expires] = this.cacheForToStaleAndExpires(cacheFor);
1237
- return [timeToMs(stale), timeToMs(expires)];
1268
+ static handleBackForward() {
1269
+ if (!navigationType.isBackForward() || !history.hasAnyState()) {
1270
+ return false;
1271
+ }
1272
+ const scrollRegions = history.getScrollRegions();
1273
+ history.decrypt().then((data) => {
1274
+ page.set(data, { preserveScroll: true, preserveState: true }).then(() => {
1275
+ Scroll.restore(scrollRegions);
1276
+ fireNavigateEvent(page.get());
1277
+ });
1278
+ }).catch(() => {
1279
+ eventHandler.onMissingHistoryItem();
1280
+ });
1281
+ return true;
1238
1282
  }
1239
- cacheForToStaleAndExpires(cacheFor) {
1240
- if (!Array.isArray(cacheFor)) {
1241
- return [cacheFor, cacheFor];
1283
+ /**
1284
+ * @link https://inertiajs.com/redirects#external-redirects
1285
+ */
1286
+ static handleLocation() {
1287
+ if (!SessionStorage.exists(SessionStorage.locationVisitKey)) {
1288
+ return false;
1242
1289
  }
1243
- switch (cacheFor.length) {
1244
- case 0:
1245
- return [0, 0];
1246
- case 1:
1247
- return [cacheFor[0], cacheFor[0]];
1248
- default:
1249
- return [cacheFor[0], cacheFor[1]];
1290
+ const locationVisit = SessionStorage.get(SessionStorage.locationVisitKey) || {};
1291
+ SessionStorage.remove(SessionStorage.locationVisitKey);
1292
+ if (typeof window !== "undefined") {
1293
+ page.setUrlHash(window.location.hash);
1250
1294
  }
1295
+ history.decrypt(page.get()).then(() => {
1296
+ const rememberedState = history.getState(history.rememberedState, {});
1297
+ const scrollRegions = history.getScrollRegions();
1298
+ page.remember(rememberedState);
1299
+ page.set(page.get(), {
1300
+ preserveScroll: locationVisit.preserveScroll,
1301
+ preserveState: true
1302
+ }).then(() => {
1303
+ if (locationVisit.preserveScroll) {
1304
+ Scroll.restore(scrollRegions);
1305
+ }
1306
+ fireNavigateEvent(page.get());
1307
+ });
1308
+ }).catch(() => {
1309
+ eventHandler.onMissingHistoryItem();
1310
+ });
1311
+ return true;
1251
1312
  }
1252
- clearTimer(params) {
1253
- const timer = this.removalTimers.find((removalTimer) => {
1254
- return this.paramsAreEqual(removalTimer.params, params);
1313
+ static handleDefault() {
1314
+ if (typeof window !== "undefined") {
1315
+ page.setUrlHash(window.location.hash);
1316
+ }
1317
+ page.set(page.get(), { preserveScroll: true, preserveState: true }).then(() => {
1318
+ if (navigationType.isReload()) {
1319
+ Scroll.restore(history.getScrollRegions());
1320
+ } else {
1321
+ Scroll.scrollToAnchor();
1322
+ }
1323
+ fireNavigateEvent(page.get());
1255
1324
  });
1256
- if (timer) {
1257
- clearTimeout(timer.timer);
1258
- this.removalTimers = this.removalTimers.filter((removalTimer) => removalTimer !== timer);
1325
+ }
1326
+ };
1327
+
1328
+ // src/poll.ts
1329
+ var Poll = class {
1330
+ constructor(interval, cb, options) {
1331
+ this.id = null;
1332
+ this.throttle = false;
1333
+ this.keepAlive = false;
1334
+ this.cbCount = 0;
1335
+ this.keepAlive = options.keepAlive ?? false;
1336
+ this.cb = cb;
1337
+ this.interval = interval;
1338
+ if (options.autoStart ?? true) {
1339
+ this.start();
1259
1340
  }
1260
1341
  }
1261
- scheduleForRemoval(params, expiresIn) {
1342
+ stop() {
1343
+ if (this.id) {
1344
+ clearInterval(this.id);
1345
+ }
1346
+ }
1347
+ start() {
1262
1348
  if (typeof window === "undefined") {
1263
1349
  return;
1264
1350
  }
1265
- this.clearTimer(params);
1266
- if (expiresIn > 0) {
1267
- const timer = window.setTimeout(() => this.remove(params), expiresIn);
1268
- this.removalTimers.push({
1269
- params,
1270
- timer
1271
- });
1272
- }
1273
- }
1274
- get(params) {
1275
- return this.findCached(params) || this.findInFlight(params);
1276
- }
1277
- use(prefetched, params) {
1278
- const id = `${params.url.pathname}-${Date.now()}-${Math.random().toString(36).substring(7)}`;
1279
- this.currentUseId = id;
1280
- return prefetched.response.then((response) => {
1281
- if (this.currentUseId !== id) {
1282
- return;
1351
+ this.stop();
1352
+ this.id = window.setInterval(() => {
1353
+ if (!this.throttle || this.cbCount % 10 === 0) {
1354
+ this.cb();
1283
1355
  }
1284
- response.mergeParams({ ...params, onPrefetched: () => {
1285
- } });
1286
- this.removeSingleUseItems(params);
1287
- return response.handle();
1288
- });
1289
- }
1290
- removeSingleUseItems(params) {
1291
- this.cached = this.cached.filter((prefetched) => {
1292
- if (!this.paramsAreEqual(prefetched.params, params)) {
1293
- return true;
1356
+ if (this.throttle) {
1357
+ this.cbCount++;
1294
1358
  }
1295
- return !prefetched.singleUse;
1296
- });
1359
+ }, this.interval);
1297
1360
  }
1298
- findCached(params) {
1299
- return this.cached.find((prefetched) => {
1300
- return this.paramsAreEqual(prefetched.params, params);
1301
- }) || null;
1361
+ isInBackground(hidden) {
1362
+ this.throttle = this.keepAlive ? false : hidden;
1363
+ if (this.throttle) {
1364
+ this.cbCount = 0;
1365
+ }
1302
1366
  }
1303
- findInFlight(params) {
1304
- return this.inFlightRequests.find((prefetched) => {
1305
- return this.paramsAreEqual(prefetched.params, params);
1306
- }) || null;
1367
+ };
1368
+
1369
+ // src/polls.ts
1370
+ var Polls = class {
1371
+ constructor() {
1372
+ this.polls = [];
1373
+ this.setupVisibilityListener();
1307
1374
  }
1308
- withoutPurposePrefetchHeader(params) {
1309
- const newParams = cloneDeep2(params);
1310
- if (newParams.headers["Purpose"] === "prefetch") {
1311
- delete newParams.headers["Purpose"];
1312
- }
1313
- return newParams;
1375
+ add(interval, cb, options) {
1376
+ const poll = new Poll(interval, cb, options);
1377
+ this.polls.push(poll);
1378
+ return {
1379
+ stop: () => poll.stop(),
1380
+ start: () => poll.start()
1381
+ };
1314
1382
  }
1315
- paramsAreEqual(params1, params2) {
1316
- return objectsAreEqual(
1317
- this.withoutPurposePrefetchHeader(params1),
1318
- this.withoutPurposePrefetchHeader(params2),
1319
- [
1320
- "showProgress",
1321
- "replace",
1322
- "prefetch",
1323
- "preserveScroll",
1324
- "preserveState",
1325
- "onBefore",
1326
- "onBeforeUpdate",
1327
- "onStart",
1328
- "onProgress",
1329
- "onFinish",
1330
- "onCancel",
1331
- "onSuccess",
1332
- "onError",
1333
- "onPrefetched",
1334
- "onCancelToken",
1335
- "onPrefetching",
1336
- "async",
1337
- "viewTransition"
1338
- ]
1383
+ clear() {
1384
+ this.polls.forEach((poll) => poll.stop());
1385
+ this.polls = [];
1386
+ }
1387
+ setupVisibilityListener() {
1388
+ if (typeof document === "undefined") {
1389
+ return;
1390
+ }
1391
+ document.addEventListener(
1392
+ "visibilitychange",
1393
+ () => {
1394
+ this.polls.forEach((poll) => poll.isInBackground(document.hidden));
1395
+ },
1396
+ false
1339
1397
  );
1340
1398
  }
1341
1399
  };
1342
- var prefetchedRequests = new PrefetchedRequests();
1400
+ var polls = new Polls();
1343
1401
 
1344
1402
  // src/request.ts
1345
1403
  import { default as axios } from "axios";
@@ -1386,6 +1444,9 @@ var RequestParams = class _RequestParams {
1386
1444
  isPartial() {
1387
1445
  return this.params.only.length > 0 || this.params.except.length > 0 || this.params.reset.length > 0;
1388
1446
  }
1447
+ isDeferredPropsRequest() {
1448
+ return this.params.deferredProps === true;
1449
+ }
1389
1450
  onCancelToken(cb) {
1390
1451
  this.params.onCancelToken({
1391
1452
  cancel: cb
@@ -1644,6 +1705,9 @@ var Response = class _Response {
1644
1705
  mergeParams(params) {
1645
1706
  this.requestParams.merge(params);
1646
1707
  }
1708
+ getPageResponse() {
1709
+ return this.response.data = this.getDataFromResponse(this.response.data);
1710
+ }
1647
1711
  async handleNonInertiaResponse() {
1648
1712
  if (this.isLocationVisit()) {
1649
1713
  const locationUrl = hrefToUrl(this.getHeader("x-inertia-location"));
@@ -1694,11 +1758,12 @@ var Response = class _Response {
1694
1758
  }
1695
1759
  }
1696
1760
  async setPage() {
1697
- const pageResponse = this.getDataFromResponse(this.response.data);
1761
+ const pageResponse = this.getPageResponse();
1698
1762
  if (!this.shouldSetPage(pageResponse)) {
1699
1763
  return Promise.resolve();
1700
1764
  }
1701
1765
  this.mergeProps(pageResponse);
1766
+ page.mergeOncePropsIntoResponse(pageResponse);
1702
1767
  this.preserveEqualProps(pageResponse);
1703
1768
  await this.setRememberedState(pageResponse);
1704
1769
  this.requestParams.setPreserveOptions(pageResponse);
@@ -1803,6 +1868,12 @@ var Response = class _Response {
1803
1868
  pageResponse.props[prop] = deepMerge(currentProp, incomingProp, prop);
1804
1869
  });
1805
1870
  pageResponse.props = { ...page.get().props, ...pageResponse.props };
1871
+ if (this.requestParams.isDeferredPropsRequest()) {
1872
+ const currentErrors = page.get().props.errors;
1873
+ if (currentErrors && Object.keys(currentErrors).length > 0) {
1874
+ pageResponse.props.errors = currentErrors;
1875
+ }
1876
+ }
1806
1877
  if (page.get().scrollProps) {
1807
1878
  pageResponse.scrollProps = {
1808
1879
  ...page.get().scrollProps || {},
@@ -1965,8 +2036,13 @@ var Request = class _Request {
1965
2036
  "X-Requested-With": "XMLHttpRequest",
1966
2037
  "X-Inertia": true
1967
2038
  };
1968
- if (page.get().version) {
1969
- headers["X-Inertia-Version"] = page.get().version;
2039
+ const page2 = page.get();
2040
+ if (page2.version) {
2041
+ headers["X-Inertia-Version"] = page2.version;
2042
+ }
2043
+ const onceProps = Object.entries(page2.onceProps || {}).filter(([, onceProp]) => !onceProp.expiresAt || onceProp.expiresAt > Date.now()).map(([key]) => key);
2044
+ if (onceProps.length > 0) {
2045
+ headers["X-Inertia-Except-Once-Props"] = onceProps.join(",");
1970
2046
  }
1971
2047
  return headers;
1972
2048
  }
@@ -2017,6 +2093,7 @@ var Router = class {
2017
2093
  maxConcurrent: Infinity,
2018
2094
  interruptible: false
2019
2095
  });
2096
+ this.clientVisitQueue = new Queue();
2020
2097
  }
2021
2098
  init({
2022
2099
  initialPage,
@@ -2055,6 +2132,9 @@ var Router = class {
2055
2132
  return this.visit(url, { preserveState: true, ...options, method: "delete" });
2056
2133
  }
2057
2134
  reload(options = {}) {
2135
+ return this.doReload(options);
2136
+ }
2137
+ doReload(options = {}) {
2058
2138
  if (typeof window === "undefined") {
2059
2139
  return;
2060
2140
  }
@@ -2243,6 +2323,9 @@ var Router = class {
2243
2323
  this.clientVisit(params);
2244
2324
  }
2245
2325
  clientVisit(params, { replace = false } = {}) {
2326
+ this.clientVisitQueue.add(() => this.performClientVisit(params, { replace }));
2327
+ }
2328
+ performClientVisit(params, { replace = false } = {}) {
2246
2329
  const current = page.get();
2247
2330
  const props = typeof params.props === "function" ? params.props(current.props) : params.props ?? current.props;
2248
2331
  const { viewTransition, onError, onFinish, onSuccess, ...pageParams } = params;
@@ -2253,7 +2336,7 @@ var Router = class {
2253
2336
  };
2254
2337
  const preserveScroll = RequestParams.resolvePreserveOption(params.preserveScroll ?? false, page2);
2255
2338
  const preserveState = RequestParams.resolvePreserveOption(params.preserveState ?? false, page2);
2256
- page.set(page2, {
2339
+ return page.set(page2, {
2257
2340
  replace,
2258
2341
  preserveScroll,
2259
2342
  preserveState,
@@ -2261,10 +2344,11 @@ var Router = class {
2261
2344
  }).then(() => {
2262
2345
  const errors = page.get().props.errors || {};
2263
2346
  if (Object.keys(errors).length === 0) {
2264
- return onSuccess?.(page.get());
2347
+ onSuccess?.(page.get());
2348
+ return;
2265
2349
  }
2266
2350
  const scopedErrors = params.errorBag ? errors[params.errorBag || ""] || {} : errors;
2267
- return onError?.(scopedErrors);
2351
+ onError?.(scopedErrors);
2268
2352
  }).finally(() => onFinish?.(params));
2269
2353
  }
2270
2354
  getPrefetchParams(href, options) {
@@ -2360,7 +2444,7 @@ var Router = class {
2360
2444
  loadDeferredProps(deferred) {
2361
2445
  if (deferred) {
2362
2446
  Object.entries(deferred).forEach(([_, group]) => {
2363
- this.reload({ only: group });
2447
+ this.doReload({ only: group, deferredProps: true });
2364
2448
  });
2365
2449
  }
2366
2450
  }
@@ -2456,6 +2540,22 @@ var requestAnimationFrame = (cb, times = 1) => {
2456
2540
  }
2457
2541
  });
2458
2542
  };
2543
+ var getInitialPageFromDOM = (id, useScriptElement = false) => {
2544
+ if (typeof window === "undefined") {
2545
+ return null;
2546
+ }
2547
+ if (!useScriptElement) {
2548
+ const el = document.getElementById(id);
2549
+ if (el?.dataset.page) {
2550
+ return JSON.parse(el.dataset.page);
2551
+ }
2552
+ }
2553
+ const scriptEl = document.querySelector(`script[data-page="${id}"][type="application/json"]`);
2554
+ if (scriptEl?.textContent) {
2555
+ return JSON.parse(scriptEl.textContent);
2556
+ }
2557
+ return null;
2558
+ };
2459
2559
 
2460
2560
  // src/formObject.ts
2461
2561
  import { get as get4, set as set4 } from "lodash-es";
@@ -3683,6 +3783,7 @@ export {
3683
3783
  config,
3684
3784
  createHeadManager,
3685
3785
  formDataToObject,
3786
+ getInitialPageFromDOM,
3686
3787
  getScrollableParent,
3687
3788
  hide2 as hideProgress,
3688
3789
  hrefToUrl,