@alignable/bifrost 0.0.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.
Files changed (79) hide show
  1. package/dist/index.d.ts +24 -0
  2. package/dist/index.d.ts.map +1 -0
  3. package/dist/index.js +1 -0
  4. package/dist/lib/PageShell.d.ts +7 -0
  5. package/dist/lib/PageShell.d.ts.map +1 -0
  6. package/dist/lib/PageShell.js +6 -0
  7. package/dist/lib/dispatchTurbolinks.d.ts +28 -0
  8. package/dist/lib/dispatchTurbolinks.d.ts.map +1 -0
  9. package/dist/lib/dispatchTurbolinks.js +5 -0
  10. package/dist/lib/domUtils.d.ts +3 -0
  11. package/dist/lib/domUtils.d.ts.map +1 -0
  12. package/dist/lib/domUtils.js +34 -0
  13. package/dist/lib/linkInterceptor.d.ts +2 -0
  14. package/dist/lib/linkInterceptor.d.ts.map +1 -0
  15. package/dist/lib/linkInterceptor.js +74 -0
  16. package/dist/lib/lruCache.d.ts +8 -0
  17. package/dist/lib/lruCache.d.ts.map +1 -0
  18. package/dist/lib/lruCache.js +25 -0
  19. package/dist/lib/mergeHead.d.ts +2 -0
  20. package/dist/lib/mergeHead.d.ts.map +1 -0
  21. package/dist/lib/mergeHead.js +126 -0
  22. package/dist/lib/navigateAnywhere.d.ts +3 -0
  23. package/dist/lib/navigateAnywhere.d.ts.map +1 -0
  24. package/dist/lib/navigateAnywhere.js +15 -0
  25. package/dist/lib/renderReact.d.ts +3 -0
  26. package/dist/lib/renderReact.d.ts.map +1 -0
  27. package/dist/lib/renderReact.js +14 -0
  28. package/dist/lib/snapshots.d.ts +9 -0
  29. package/dist/lib/snapshots.d.ts.map +1 -0
  30. package/dist/lib/snapshots.js +50 -0
  31. package/dist/lib/turbolinks.d.ts +4 -0
  32. package/dist/lib/turbolinks.d.ts.map +1 -0
  33. package/dist/lib/turbolinks.js +12 -0
  34. package/dist/proxy/pages/+config.d.ts +21 -0
  35. package/dist/proxy/pages/+config.d.ts.map +1 -0
  36. package/dist/proxy/pages/+config.js +17 -0
  37. package/dist/proxy/pages/Page.d.ts +2 -0
  38. package/dist/proxy/pages/Page.d.ts.map +1 -0
  39. package/dist/proxy/pages/Page.js +4 -0
  40. package/dist/proxy/pages/onBeforeRender.d.ts +5 -0
  41. package/dist/proxy/pages/onBeforeRender.d.ts.map +1 -0
  42. package/dist/proxy/pages/onBeforeRender.js +6 -0
  43. package/dist/proxy/pages/onRenderClient.d.ts +4 -0
  44. package/dist/proxy/pages/onRenderClient.d.ts.map +1 -0
  45. package/dist/proxy/pages/onRenderClient.js +44 -0
  46. package/dist/proxy/pages/onRenderHtml.d.ts +9 -0
  47. package/dist/proxy/pages/onRenderHtml.d.ts.map +1 -0
  48. package/dist/proxy/pages/onRenderHtml.js +46 -0
  49. package/dist/proxy/pages/restorationVisit/+config.d.ts +13 -0
  50. package/dist/proxy/pages/restorationVisit/+config.d.ts.map +1 -0
  51. package/dist/proxy/pages/restorationVisit/+config.js +14 -0
  52. package/dist/proxy/pages/restorationVisit/route.d.ts +2 -0
  53. package/dist/proxy/pages/restorationVisit/route.d.ts.map +1 -0
  54. package/dist/proxy/pages/restorationVisit/route.js +4 -0
  55. package/dist/renderer/+config.d.ts +24 -0
  56. package/dist/renderer/+config.d.ts.map +1 -0
  57. package/dist/renderer/+config.js +18 -0
  58. package/dist/renderer/_error/Page.d.ts +7 -0
  59. package/dist/renderer/_error/Page.d.ts.map +1 -0
  60. package/dist/renderer/_error/Page.js +15 -0
  61. package/dist/renderer/getDocumentProps.d.ts +3 -0
  62. package/dist/renderer/getDocumentProps.d.ts.map +1 -0
  63. package/dist/renderer/getDocumentProps.js +3 -0
  64. package/dist/renderer/onBeforeRoute.d.ts +9 -0
  65. package/dist/renderer/onBeforeRoute.d.ts.map +1 -0
  66. package/dist/renderer/onBeforeRoute.js +15 -0
  67. package/dist/renderer/onRenderClient.d.ts +4 -0
  68. package/dist/renderer/onRenderClient.d.ts.map +1 -0
  69. package/dist/renderer/onRenderClient.js +29 -0
  70. package/dist/renderer/onRenderHtml.d.ts +6 -0
  71. package/dist/renderer/onRenderHtml.d.ts.map +1 -0
  72. package/dist/renderer/onRenderHtml.js +38 -0
  73. package/dist/renderer/usePageContext.d.ts +10 -0
  74. package/dist/renderer/usePageContext.d.ts.map +1 -0
  75. package/dist/renderer/usePageContext.js +13 -0
  76. package/dist/types/internal.d.ts +52 -0
  77. package/dist/types/internal.d.ts.map +1 -0
  78. package/dist/types/internal.js +1 -0
  79. package/package.json +51 -0
@@ -0,0 +1,24 @@
1
+ import { Config } from "vite-plugin-ssr/types";
2
+ import { DocumentProps, Layout, LayoutMap } from "./types/internal";
3
+ import ProxyLibConfig from "./proxy/pages/+config";
4
+ import bifrostLibConfig from "./renderer/+config";
5
+ import { Turbolinks } from "./lib/turbolinks";
6
+ export { usePageContext } from "./renderer/usePageContext";
7
+ export { LayoutMap, DocumentProps };
8
+ type ConfigConstructor<LibConfig extends Config, T extends {
9
+ [K in keyof LibConfig["meta"]]?: any;
10
+ }> = Config & Partial<T>;
11
+ export type ProxyConfig<LayoutProps> = ConfigConstructor<typeof ProxyLibConfig, {
12
+ layoutMap: LayoutMap<LayoutProps>;
13
+ }>;
14
+ export type bifrostConfig<LayoutProps> = ConfigConstructor<typeof bifrostLibConfig, {
15
+ Layout: Layout<LayoutProps>;
16
+ layoutProps: LayoutProps;
17
+ documentProps: DocumentProps;
18
+ }>;
19
+ declare global {
20
+ interface Window {
21
+ Turbolinks: typeof Turbolinks;
22
+ }
23
+ }
24
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACpE,OAAO,cAAc,MAAM,uBAAuB,CAAC;AACnD,OAAO,gBAAgB,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAI3D,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,CAAC;AAGpC,KAAK,iBAAiB,CACpB,SAAS,SAAS,MAAM,EACxB,CAAC,SAAS;KAAG,CAAC,IAAI,MAAM,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG;CAAE,IAChD,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;AAExB,MAAM,MAAM,WAAW,CAAC,WAAW,IAAI,iBAAiB,CACtD,OAAO,cAAc,EACrB;IACE,SAAS,EAAE,SAAS,CAAC,WAAW,CAAC,CAAC;CACnC,CACF,CAAC;AAEF,MAAM,MAAM,aAAa,CAAC,WAAW,IAAI,iBAAiB,CACxD,OAAO,gBAAgB,EACvB;IACE,MAAM,EAAE,MAAM,CAAC,WAAW,CAAC,CAAC;IAC5B,WAAW,EAAE,WAAW,CAAC;IACzB,aAAa,EAAE,aAAa,CAAC;CAC9B,CACF,CAAC;AAEF,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,UAAU,EAAE,OAAO,UAAU,CAAC;KAC/B;CACF"}
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ export { usePageContext } from "./renderer/usePageContext";
@@ -0,0 +1,7 @@
1
+ import { ReactNode } from "react";
2
+ import { PageContext } from "../types/internal";
3
+ export declare function PageShell({ pageContext, children, }: {
4
+ pageContext: PageContext;
5
+ children: ReactNode;
6
+ }): JSX.Element;
7
+ //# sourceMappingURL=PageShell.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PageShell.d.ts","sourceRoot":"","sources":["../../lib/PageShell.tsx"],"names":[],"mappings":"AAAA,OAAc,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEzC,OAAO,EAAE,WAAW,EAAsB,MAAM,mBAAmB,CAAC;AAEpE,wBAAgB,SAAS,CAAC,EACxB,WAAW,EACX,QAAQ,GACT,EAAE;IACD,WAAW,EAAE,WAAW,CAAC;IACzB,QAAQ,EAAE,SAAS,CAAC;CACrB,eAQA"}
@@ -0,0 +1,6 @@
1
+ import React from "react";
2
+ import { PageContextProvider } from "../renderer/usePageContext";
3
+ export function PageShell({ pageContext, children, }) {
4
+ return (React.createElement(React.StrictMode, null,
5
+ React.createElement(PageContextProvider, { pageContext: pageContext }, children)));
6
+ }
@@ -0,0 +1,28 @@
1
+ export interface TurbolinksTiming {
2
+ requestEnd: number;
3
+ requestStart: number;
4
+ visitEnd: number;
5
+ visitStart: number;
6
+ }
7
+ export type TurbolinksEvents = {
8
+ "turbolinks:click": {
9
+ url: string;
10
+ };
11
+ "turbolinks:before-visit": {
12
+ url: string;
13
+ };
14
+ "turbolinks:visit": {
15
+ url: string;
16
+ };
17
+ "turbolinks:before-cache": {};
18
+ "turbolinks:before-render": {
19
+ newBody: string;
20
+ };
21
+ "turbolinks:render": {};
22
+ "turbolinks:load": {
23
+ url: string;
24
+ timing?: TurbolinksTiming;
25
+ };
26
+ };
27
+ export declare function dispatchTurbolinks<E extends keyof TurbolinksEvents>(name: E, data: TurbolinksEvents[E], target?: EventTarget): void;
28
+ //# sourceMappingURL=dispatchTurbolinks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dispatchTurbolinks.d.ts","sourceRoot":"","sources":["../../lib/dispatchTurbolinks.ts"],"names":[],"mappings":"AACA,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB;AAGD,MAAM,MAAM,gBAAgB,GAAG;IAC7B,kBAAkB,EAAE;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IACpC,yBAAyB,EAAE;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3C,kBAAkB,EAAE;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IACpC,yBAAyB,EAAE,EAAE,CAAC;IAC9B,0BAA0B,EAAE;QAAE,OAAO,EAAE,MAAM,CAAA;KAAC,CAAC;IAC/C,mBAAmB,EAAE,EAAE,CAAC;IACxB,iBAAiB,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,gBAAgB,CAAA;KAAE,CAAC;CAC/D,CAAC;AAEF,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,MAAM,gBAAgB,EACjE,IAAI,EAAE,CAAC,EACP,IAAI,EAAE,gBAAgB,CAAC,CAAC,CAAC,EACzB,MAAM,GAAE,WAAsB,QAK/B"}
@@ -0,0 +1,5 @@
1
+ export function dispatchTurbolinks(name, data, target = document) {
2
+ const event = new Event(name, { bubbles: true, cancelable: true });
3
+ event.data = data;
4
+ target.dispatchEvent(event);
5
+ }
@@ -0,0 +1,3 @@
1
+ export declare function createScriptElement(element: Element, cb?: () => void): Element;
2
+ export declare function activateNewBodyScriptElements(newScriptElements: HTMLScriptElement[]): void;
3
+ //# sourceMappingURL=domUtils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"domUtils.d.ts","sourceRoot":"","sources":["../../lib/domUtils.ts"],"names":[],"mappings":"AASA,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,CAAC,EAAE,MAAM,IAAI,WAepE;AAQD,wBAAgB,6BAA6B,CAC3C,iBAAiB,EAAE,iBAAiB,EAAE,QAMvC"}
@@ -0,0 +1,34 @@
1
+ function copyElementAttributes(destinationElement, sourceElement) {
2
+ for (const { name, value } of Array.from(sourceElement.attributes)) {
3
+ destinationElement.setAttribute(name, value);
4
+ }
5
+ }
6
+ export function createScriptElement(element, cb) {
7
+ if (element.getAttribute("data-turbolinks-eval") == "false") {
8
+ return element;
9
+ }
10
+ else {
11
+ const createdScriptElement = document.createElement("script");
12
+ createdScriptElement.textContent = element.textContent;
13
+ // async false makes scripts run in-order. it wont block js execution (thankfully)
14
+ // https://github.com/turbolinks/turbolinks/issues/282#issuecomment-355731712
15
+ createdScriptElement.async = false;
16
+ copyElementAttributes(createdScriptElement, element);
17
+ if (cb) {
18
+ createdScriptElement.addEventListener("load", cb);
19
+ }
20
+ return createdScriptElement;
21
+ }
22
+ }
23
+ function replaceElementWithElement(fromElement, toElement) {
24
+ const parentElement = fromElement.parentElement;
25
+ if (parentElement) {
26
+ return parentElement.replaceChild(toElement, fromElement);
27
+ }
28
+ }
29
+ export function activateNewBodyScriptElements(newScriptElements) {
30
+ for (const inertScriptElement of newScriptElements) {
31
+ const activatedScriptElement = createScriptElement(inertScriptElement);
32
+ replaceElementWithElement(inertScriptElement, activatedScriptElement);
33
+ }
34
+ }
@@ -0,0 +1,2 @@
1
+ export declare function turbolinksClickListener(event: MouseEvent): void;
2
+ //# sourceMappingURL=linkInterceptor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"linkInterceptor.d.ts","sourceRoot":"","sources":["../../lib/linkInterceptor.ts"],"names":[],"mappings":"AA2EA,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,UAAU,QAgBxD"}
@@ -0,0 +1,74 @@
1
+ import { dispatchTurbolinks } from "./dispatchTurbolinks";
2
+ import { Turbolinks } from "./turbolinks";
3
+ function isAction(action) {
4
+ return action == "advance" || action == "replace" || action == "restore";
5
+ }
6
+ // TODO: polyfilled closest may not be required. check caniuse?
7
+ const closest = (() => {
8
+ const html = typeof window !== 'undefined' && document.documentElement;
9
+ const match = html.matches ||
10
+ html.webkitMatchesSelector ||
11
+ html.msMatchesSelector ||
12
+ html.mozMatchesSelector;
13
+ const closest = (html && html.closest) ||
14
+ function (selector) {
15
+ let element = this;
16
+ while (element) {
17
+ if (match.call(element, selector)) {
18
+ return element;
19
+ }
20
+ else {
21
+ element = element.parentElement;
22
+ }
23
+ }
24
+ };
25
+ return function (element, selector) {
26
+ return closest.call(element, selector);
27
+ };
28
+ })();
29
+ function elementIsVisitable(element) {
30
+ const container = closest(element, "[data-turbolinks]");
31
+ if (container) {
32
+ return container.getAttribute("data-turbolinks") != "false";
33
+ }
34
+ else {
35
+ return true;
36
+ }
37
+ }
38
+ function getVisitableLinkForTarget(target) {
39
+ if (target instanceof Element && elementIsVisitable(target)) {
40
+ return closest(target, "a[href]:not([target]):not([download])");
41
+ }
42
+ return null;
43
+ }
44
+ // stolen from turbolinks controller.ts
45
+ function clickEventIsSignificant(event) {
46
+ return !((event.target && event.target.isContentEditable) ||
47
+ event.defaultPrevented ||
48
+ event.which > 1 ||
49
+ event.altKey ||
50
+ event.ctrlKey ||
51
+ event.metaKey ||
52
+ event.shiftKey);
53
+ }
54
+ function getActionForLink(link) {
55
+ const action = link.getAttribute("data-turbolinks-action");
56
+ return isAction(action) ? action : "advance";
57
+ }
58
+ export function turbolinksClickListener(event) {
59
+ if (clickEventIsSignificant(event)) {
60
+ const link = getVisitableLinkForTarget(event.target);
61
+ if (link) {
62
+ const location = link.getAttribute("href") || "";
63
+ if (location) {
64
+ const action = getActionForLink(link);
65
+ event.preventDefault();
66
+ // TODO: technically canceling these events should do various things, but afaict we never do that in alignableweb
67
+ dispatchTurbolinks("turbolinks:click", { url: location }, link);
68
+ dispatchTurbolinks("turbolinks:before-visit", { url: location });
69
+ dispatchTurbolinks("turbolinks:visit", { url: location });
70
+ Turbolinks.visit(location, { action });
71
+ }
72
+ }
73
+ }
74
+ }
@@ -0,0 +1,8 @@
1
+ export declare class LruCache<T> {
2
+ private values;
3
+ private maxEntries;
4
+ constructor(maxEntries: number);
5
+ get(key: string): T | undefined;
6
+ put(key: string, value: T): void;
7
+ }
8
+ //# sourceMappingURL=lruCache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lruCache.d.ts","sourceRoot":"","sources":["../../lib/lruCache.ts"],"names":[],"mappings":"AAAA,qBAAa,QAAQ,CAAC,CAAC;IACrB,OAAO,CAAC,MAAM,CAAwC;IACtD,OAAO,CAAC,UAAU,CAAC;gBAEP,UAAU,EAAE,MAAM;IAIvB,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS;IAa/B,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;CAUjC"}
@@ -0,0 +1,25 @@
1
+ export class LruCache {
2
+ constructor(maxEntries) {
3
+ this.values = new Map();
4
+ this.maxEntries = maxEntries;
5
+ }
6
+ get(key) {
7
+ const hasKey = this.values.has(key);
8
+ let entry;
9
+ if (hasKey) {
10
+ // peek the entry, re-insert for LRU strategy
11
+ entry = this.values.get(key);
12
+ this.values.delete(key);
13
+ this.values.set(key, entry);
14
+ }
15
+ return entry;
16
+ }
17
+ put(key, value) {
18
+ if (this.values.size >= this.maxEntries) {
19
+ // least-recently used cache eviction strategy
20
+ const keyToDelete = this.values.keys().next().value;
21
+ this.values.delete(keyToDelete);
22
+ }
23
+ this.values.set(key, value);
24
+ }
25
+ }
@@ -0,0 +1,2 @@
1
+ export declare function mergeHead(head: string): void;
2
+ //# sourceMappingURL=mergeHead.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mergeHead.d.ts","sourceRoot":"","sources":["../../lib/mergeHead.ts"],"names":[],"mappings":"AAUA,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,QAuBrC"}
@@ -0,0 +1,126 @@
1
+ import { dispatchTurbolinks } from "./dispatchTurbolinks";
2
+ import { activateNewBodyScriptElements, createScriptElement } from "./domUtils";
3
+ const allHeadScriptsEverRun = {};
4
+ let firstLoad = true;
5
+ // takes in innerHTML of head
6
+ export function mergeHead(head) {
7
+ const parsed = document.createRange().createContextualFragment(head); // Create a 'tiny' document and parse the html string
8
+ const newHead = categorizeHead(parsed);
9
+ const oldHead = categorizeHead(document.head);
10
+ if (!trackedScriptsIdentical(oldHead.scripts, newHead.scripts)) {
11
+ window.location.reload();
12
+ }
13
+ if (firstLoad) {
14
+ // TODO: messy code
15
+ for (const element of oldHead.scripts) {
16
+ allHeadScriptsEverRun[element.outerHTML] = {
17
+ tracked: elementIsTracked(element),
18
+ };
19
+ }
20
+ firstLoad = false;
21
+ }
22
+ copyNewHeadStylesheetElements(newHead.stylesheets, oldHead.stylesheets);
23
+ removeCurrentHeadProvisionalElements(oldHead.provisional);
24
+ copyNewHeadProvisionalElements(newHead.provisional);
25
+ copyNewHeadScriptElements(newHead.scripts);
26
+ }
27
+ function trackedScriptsIdentical(prev, next) {
28
+ return (prev
29
+ .filter(elementIsTracked)
30
+ .map((s) => s.outerHTML)
31
+ .join() ===
32
+ next
33
+ .filter(elementIsTracked)
34
+ .map((s) => s.outerHTML)
35
+ .join());
36
+ }
37
+ function copyNewHeadStylesheetElements(next, prev) {
38
+ const existing = prev.map((s) => s.outerHTML);
39
+ for (const element of next) {
40
+ if (!existing.includes(element.outerHTML)) {
41
+ document.head.appendChild(element);
42
+ }
43
+ }
44
+ }
45
+ function copyNewHeadScriptElements(next) {
46
+ let blockingLoaded = [];
47
+ function dispatch() {
48
+ const scripts = document.body
49
+ .querySelector("#proxied-body")
50
+ .querySelectorAll("script");
51
+ // TODO: maybe this goes in onTransitionEnd? Need to test.
52
+ activateNewBodyScriptElements(Array.from(scripts));
53
+ focusFirstAutofocusableElement();
54
+ dispatchTurbolinks("turbolinks:render", {});
55
+ dispatchTurbolinks("turbolinks:load", { url: window.location.href });
56
+ }
57
+ for (const element of next) {
58
+ const runBefore = element.outerHTML in allHeadScriptsEverRun;
59
+ if (!runBefore) {
60
+ let cb;
61
+ if (!element.defer && element.src) {
62
+ const idx = blockingLoaded.length;
63
+ cb = () => {
64
+ blockingLoaded[idx] = true;
65
+ if (blockingLoaded.every((v) => v)) {
66
+ dispatch();
67
+ }
68
+ };
69
+ blockingLoaded.push(false);
70
+ }
71
+ document.head.appendChild(createScriptElement(element, cb));
72
+ allHeadScriptsEverRun[element.outerHTML] = {
73
+ tracked: elementIsTracked(element),
74
+ };
75
+ }
76
+ }
77
+ if (blockingLoaded.length === 0) {
78
+ //TODO: raf waits for react to run... not 100% sure of the reliability
79
+ requestAnimationFrame(() => requestAnimationFrame(dispatch));
80
+ }
81
+ }
82
+ function removeCurrentHeadProvisionalElements(prev) {
83
+ for (const element of prev) {
84
+ document.head.removeChild(element);
85
+ }
86
+ }
87
+ function copyNewHeadProvisionalElements(next) {
88
+ for (const element of next) {
89
+ document.head.appendChild(element);
90
+ }
91
+ }
92
+ function focusFirstAutofocusableElement() {
93
+ const element = document.body.querySelector("[autofocus]");
94
+ if (element && "focus" in element && typeof element.focus === "function") {
95
+ element.focus();
96
+ }
97
+ }
98
+ function elementIsTracked(element) {
99
+ return element.getAttribute("data-turbolinks-track") == "reload";
100
+ }
101
+ function elementIsScript(element) {
102
+ const tagName = element.tagName.toLowerCase();
103
+ return tagName == "script";
104
+ }
105
+ function elementIsStylesheet(element) {
106
+ const tagName = element.tagName.toLowerCase();
107
+ return (tagName == "style" ||
108
+ (tagName == "link" && element.getAttribute("rel") == "stylesheet"));
109
+ }
110
+ function categorizeHead(head) {
111
+ const scripts = [];
112
+ const stylesheets = [];
113
+ const provisional = [];
114
+ for (const element of head.children) {
115
+ if (elementIsScript(element)) {
116
+ scripts.push(element);
117
+ }
118
+ else if (elementIsStylesheet(element)) {
119
+ stylesheets.push(element);
120
+ }
121
+ else {
122
+ provisional.push(element);
123
+ }
124
+ }
125
+ return { scripts, stylesheets, provisional };
126
+ }
@@ -0,0 +1,3 @@
1
+ import { navigate } from "vite-plugin-ssr/client/router";
2
+ export declare function navigateAnywhere(to?: string, opts?: Parameters<typeof navigate>[1]): boolean;
3
+ //# sourceMappingURL=navigateAnywhere.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"navigateAnywhere.d.ts","sourceRoot":"","sources":["../../lib/navigateAnywhere.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,+BAA+B,CAAC;AAIzD,wBAAgB,gBAAgB,CAC9B,EAAE,CAAC,EAAE,MAAM,EACX,IAAI,CAAC,EAAE,UAAU,CAAC,OAAO,QAAQ,CAAC,CAAC,CAAC,CAAC,WAWtC"}
@@ -0,0 +1,15 @@
1
+ import { navigate } from "vite-plugin-ssr/client/router";
2
+ // handle internal and external navigation
3
+ // returns whether or not we redirected
4
+ export function navigateAnywhere(to, opts) {
5
+ if (to) {
6
+ const url = new URL(to, window.location.href);
7
+ if (url.host !== window.location.host) {
8
+ window.location.href = to;
9
+ }
10
+ else {
11
+ navigate(url.pathname + url.hash + url.search, opts);
12
+ }
13
+ }
14
+ return !!to;
15
+ }
@@ -0,0 +1,3 @@
1
+ import { ReactNode } from "react";
2
+ export declare function renderReact(page: ReactNode, isHydration: boolean): void;
3
+ //# sourceMappingURL=renderReact.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"renderReact.d.ts","sourceRoot":"","sources":["../../lib/renderReact.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAKlC,wBAAgB,WAAW,CAAC,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,OAAO,QAUhE"}
@@ -0,0 +1,14 @@
1
+ import { createRoot, hydrateRoot } from "react-dom/client";
2
+ let root;
3
+ export function renderReact(page, isHydration) {
4
+ const container = document.getElementById("page-view");
5
+ if (isHydration) {
6
+ root = hydrateRoot(container, page);
7
+ }
8
+ else {
9
+ if (!root) {
10
+ root = createRoot(container);
11
+ }
12
+ root.render(page);
13
+ }
14
+ }
@@ -0,0 +1,9 @@
1
+ import { PageContextProxyClient } from "../types/internal";
2
+ type Snapshot = Pick<Extract<PageContextProxyClient, {
3
+ isHydration: false;
4
+ }>, "proxySendClient" | "layout" | "layoutProps">;
5
+ export declare function writeRestorationIdentifier(pageContext: PageContextProxyClient): void;
6
+ export declare function cacheProxiedBody(): void;
7
+ export declare function getSnapshot(): Snapshot | undefined;
8
+ export {};
9
+ //# sourceMappingURL=snapshots.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"snapshots.d.ts","sourceRoot":"","sources":["../../lib/snapshots.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAS,MAAM,mBAAmB,CAAC;AAKlE,KAAK,QAAQ,GAAG,IAAI,CAClB,OAAO,CAAC,sBAAsB,EAAE;IAAE,WAAW,EAAE,KAAK,CAAA;CAAE,CAAC,EACvD,iBAAiB,GAAG,QAAQ,GAAG,aAAa,CAC7C,CAAC;AAMF,wBAAgB,0BAA0B,CACxC,WAAW,EAAE,sBAAsB,QAkBpC;AASD,wBAAgB,gBAAgB,SAiB/B;AAGD,wBAAgB,WAAW,IAAI,QAAQ,GAAG,SAAS,CAGlD"}
@@ -0,0 +1,50 @@
1
+ import { dispatchTurbolinks } from "./dispatchTurbolinks";
2
+ import { v4 as uuidv4 } from "uuid";
3
+ import { LruCache } from "./lruCache";
4
+ const snapshots = new LruCache(10);
5
+ let lastRestorationIdentifier;
6
+ export function writeRestorationIdentifier(pageContext) {
7
+ if (history.state.restorationIdentifier) {
8
+ return;
9
+ }
10
+ lastRestorationIdentifier = uuidv4();
11
+ history.replaceState({
12
+ restorationIdentifier: lastRestorationIdentifier,
13
+ // these two could go in snapshot instead...
14
+ ...history.state,
15
+ }, "");
16
+ snapshots.put(lastRestorationIdentifier, {
17
+ layout: pageContext.layout,
18
+ layoutProps: pageContext.layoutProps,
19
+ });
20
+ }
21
+ /*
22
+ this is not working rn because we need to put the restoration identifier onto the history stack BEFORE navigate calls pushState
23
+ otherwise it is too late and we can only modify the new page's state...
24
+
25
+ what if we add the restoration identifier on page load?
26
+ how does react history state libs do it?
27
+ */
28
+ export function cacheProxiedBody() {
29
+ if (document.getElementById("proxied-body")) {
30
+ dispatchTurbolinks("turbolinks:before-cache", {});
31
+ const bodyAttrs = {};
32
+ document.body.getAttributeNames().forEach((name) => {
33
+ bodyAttrs[name] = document.body.getAttribute(name);
34
+ }, {});
35
+ snapshots.put(lastRestorationIdentifier, {
36
+ ...snapshots.get(lastRestorationIdentifier),
37
+ proxySendClient: {
38
+ head: document.head.innerHTML,
39
+ body: document.getElementById("proxied-body").innerHTML,
40
+ bodyAttrs,
41
+ },
42
+ });
43
+ }
44
+ }
45
+ const onBrowser = typeof window !== "undefined";
46
+ export function getSnapshot() {
47
+ if (!onBrowser)
48
+ return;
49
+ return snapshots.get(history.state.restorationIdentifier);
50
+ }
@@ -0,0 +1,4 @@
1
+ export declare const Turbolinks: {
2
+ visit: (location: import("turbolinks/dist/location").Locatable, options?: Partial<import("turbolinks/dist/controller").VisitOptions> | undefined) => void;
3
+ };
4
+ //# sourceMappingURL=turbolinks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"turbolinks.d.ts","sourceRoot":"","sources":["../../lib/turbolinks.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,UAAU;;CAOtB,CAAC"}
@@ -0,0 +1,12 @@
1
+ import { navigateAnywhere } from "./navigateAnywhere";
2
+ export const Turbolinks = {
3
+ visit: function (location, options) {
4
+ const href = location.toString();
5
+ navigateAnywhere(href, {
6
+ overwriteLastHistoryEntry: options?.action === "replace",
7
+ });
8
+ },
9
+ };
10
+ if (typeof window !== "undefined" && !window.Turbolinks) {
11
+ window.Turbolinks = Turbolinks;
12
+ }
@@ -0,0 +1,21 @@
1
+ import onBeforeRender from "@alignable/bifrost/proxy/pages/onBeforeRender";
2
+ import onRenderClient from "@alignable/bifrost/proxy/pages/onRenderClient";
3
+ import onRenderHtml from "@alignable/bifrost/proxy/pages/onRenderHtml";
4
+ import Page from "@alignable/bifrost/proxy/pages/Page";
5
+ declare const _default: {
6
+ route: string;
7
+ onBeforeRender: typeof onBeforeRender;
8
+ onRenderClient: typeof onRenderClient;
9
+ onRenderHtml: typeof onRenderHtml;
10
+ Page: typeof Page;
11
+ passToClient: string[];
12
+ clientRouting: true;
13
+ hydrationCanBeAborted: true;
14
+ meta: {
15
+ layoutMap: {
16
+ env: "server-and-client";
17
+ };
18
+ };
19
+ };
20
+ export default _default;
21
+ //# sourceMappingURL=+config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"+config.d.ts","sourceRoot":"","sources":["../../../proxy/pages/+config.ts"],"names":[],"mappings":"AACA,OAAO,cAAc,MAAM,+CAA+C,CAAC;AAC3E,OAAO,cAAc,MAAM,+CAA+C,CAAC;AAC3E,OAAO,YAAY,MAAM,6CAA6C,CAAC;AACvE,OAAO,IAAI,MAAM,qCAAqC,CAAC;;;;;;;;;;;;;;;;AAEvD,wBAYmB"}
@@ -0,0 +1,17 @@
1
+ import onBeforeRender from "@alignable/bifrost/proxy/pages/onBeforeRender";
2
+ import onRenderClient from "@alignable/bifrost/proxy/pages/onRenderClient";
3
+ import onRenderHtml from "@alignable/bifrost/proxy/pages/onRenderHtml";
4
+ import Page from "@alignable/bifrost/proxy/pages/Page";
5
+ export default {
6
+ route: "/*",
7
+ onBeforeRender,
8
+ onRenderClient,
9
+ onRenderHtml,
10
+ Page,
11
+ passToClient: ["proxySendClient", "layout", "layoutProps", "redirectTo"],
12
+ clientRouting: true,
13
+ hydrationCanBeAborted: true,
14
+ meta: {
15
+ layoutMap: { env: "server-and-client" },
16
+ },
17
+ };
@@ -0,0 +1,2 @@
1
+ export default function Page(): null;
2
+ //# sourceMappingURL=Page.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Page.d.ts","sourceRoot":"","sources":["../../../proxy/pages/Page.tsx"],"names":[],"mappings":"AACA,MAAM,CAAC,OAAO,UAAU,IAAI,SAE3B"}
@@ -0,0 +1,4 @@
1
+ /* This really should not be neccessary. VPS v1 beta turns off client routing if no Page detected - maybe a bug */
2
+ export default function Page() {
3
+ return null;
4
+ }
@@ -0,0 +1,5 @@
1
+ import { PageContextProxyServer } from "../../types/internal";
2
+ export default function onBeforeRender(pageContext: PageContextProxyServer): Promise<{
3
+ pageContext: {};
4
+ } | undefined>;
5
+ //# sourceMappingURL=onBeforeRender.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"onBeforeRender.d.ts","sourceRoot":"","sources":["../../../proxy/pages/onBeforeRender.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAG9D,wBAA8B,cAAc,CAAC,WAAW,EAAE,sBAAsB;;eAI/E"}
@@ -0,0 +1,6 @@
1
+ // Indicates to VPS that this route requires a data fetch to grab pageContext
2
+ export default async function onBeforeRender(pageContext) {
3
+ if (pageContext.proxy) {
4
+ return { pageContext: {} };
5
+ }
6
+ }
@@ -0,0 +1,4 @@
1
+ import { PageContextProxyClient } from "../../types/internal";
2
+ import "../../lib/turbolinks";
3
+ export default function onRenderClient(pageContext: PageContextProxyClient): Promise<void>;
4
+ //# sourceMappingURL=onRenderClient.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"onRenderClient.d.ts","sourceRoot":"","sources":["../../../proxy/pages/onRenderClient.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAS9D,OAAO,sBAAsB,CAAC;AAE9B,wBAA8B,cAAc,CAC1C,WAAW,EAAE,sBAAsB,iBAgDpC"}
@@ -0,0 +1,44 @@
1
+ import React from "react";
2
+ import { renderReact } from "../../lib/renderReact";
3
+ import { PageShell } from "../../lib/PageShell";
4
+ import { turbolinksClickListener } from "../../lib/linkInterceptor";
5
+ import { dispatchTurbolinks } from "../../lib/dispatchTurbolinks";
6
+ import { mergeHead } from "../../lib/mergeHead";
7
+ import { cacheProxiedBody, writeRestorationIdentifier, } from "../../lib/snapshots";
8
+ import { navigateAnywhere } from "../../lib/navigateAnywhere";
9
+ import "../../lib/turbolinks";
10
+ export default async function onRenderClient(pageContext) {
11
+ if (navigateAnywhere(pageContext.redirectTo))
12
+ return;
13
+ let body;
14
+ const { layoutProps, layout } = pageContext;
15
+ const Layout = pageContext.config.layoutMap[layout];
16
+ if (pageContext.isHydration) {
17
+ // During hydration of initial ssr, body is in dom, not page props (to avoid double-send)
18
+ body = document.getElementById("proxied-body").innerHTML;
19
+ }
20
+ else {
21
+ const { proxySendClient: proxy } = pageContext;
22
+ if (!proxy) {
23
+ console.error("proxy/+onRenderClient did not receive proxySendClient nor is there a cached snapshot");
24
+ return;
25
+ }
26
+ cacheProxiedBody();
27
+ dispatchTurbolinks("turbolinks:before-render", { newBody: proxy.body });
28
+ body = proxy.body;
29
+ document.body
30
+ .getAttributeNames()
31
+ .forEach((n) => document.body.removeAttribute(n));
32
+ for (const [name, value] of Object.entries(proxy.bodyAttrs)) {
33
+ document.body.setAttribute(name, value);
34
+ }
35
+ mergeHead(proxy.head);
36
+ }
37
+ writeRestorationIdentifier(pageContext);
38
+ // addEventListener de-dupes so we are safe to just blindly call this every time
39
+ // non-proxy pages remove the listener
40
+ document.addEventListener("click", turbolinksClickListener);
41
+ renderReact(React.createElement(PageShell, { key: pageContext.urlOriginal, pageContext: pageContext },
42
+ React.createElement(Layout, { ...layoutProps },
43
+ React.createElement("div", { id: "proxied-body", dangerouslySetInnerHTML: { __html: body } }))), pageContext.isHydration);
44
+ }
@@ -0,0 +1,9 @@
1
+ import { PageContextProxyServer } from "../../types/internal";
2
+ export default function onRenderHtml(pageContext: PageContextProxyServer): Promise<{
3
+ documentHtml: import("vite-plugin-ssr/dist/types/node/runtime/html/renderHtml").TemplateWrapped;
4
+ pageContext: {};
5
+ } | {
6
+ documentHtml?: undefined;
7
+ pageContext?: undefined;
8
+ }>;
9
+ //# sourceMappingURL=onRenderHtml.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"onRenderHtml.d.ts","sourceRoot":"","sources":["../../../proxy/pages/onRenderHtml.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAG9D,wBAA8B,YAAY,CACxC,WAAW,EAAE,sBAAsB;;;;;;GAsDpC"}
@@ -0,0 +1,46 @@
1
+ import React from "react";
2
+ import ReactDOMServer from "react-dom/server";
3
+ import { dangerouslySkipEscape, escapeInject } from "vite-plugin-ssr/server";
4
+ import { PageShell } from "../../lib/PageShell";
5
+ export default async function onRenderHtml(pageContext) {
6
+ if (pageContext.proxy) {
7
+ const { proxy: { head, body, bodyAttrs }, layoutProps, layout, } = pageContext;
8
+ const Layout = pageContext.config.layoutMap[layout];
9
+ if (!Layout)
10
+ throw new Error(`${layout} layout not found`);
11
+ const pageHtml = ReactDOMServer.renderToString(React.createElement(PageShell, { pageContext: pageContext },
12
+ React.createElement(Layout, { ...layoutProps },
13
+ React.createElement("div", { id: "proxied-body", dangerouslySetInnerHTML: { __html: body } }))));
14
+ const documentHtml = escapeInject `
15
+ <!DOCTYPE html>
16
+ <html>
17
+ <head>
18
+ ${dangerouslySkipEscape(head)}
19
+ ${
20
+ // We need to fire turbolinks:load exactly on DCL, so it must be a blocking head script to catch DCL event.
21
+ // Vite loads scripts with type="module" so the rest of our code will show up too late.
22
+ // TODO: figure out how to bundle this better. at least read from a .js file
23
+ dangerouslySkipEscape(`<script>
24
+ addEventListener("DOMContentLoaded", () => {
25
+ const event = new Event("turbolinks:load", { bubbles: true, cancelable: true });
26
+ event.data = {url: window.location.href};
27
+ document.dispatchEvent(event);
28
+ })
29
+ </script>`)}
30
+ </head>
31
+ <body ${dangerouslySkipEscape(Object.entries(bodyAttrs)
32
+ .map(([name, value]) => `${name}="${value}"`)
33
+ .join(" "))}>
34
+ <div id="page-view">${dangerouslySkipEscape(pageHtml)}</div>
35
+ </body>
36
+ </html>`;
37
+ return {
38
+ documentHtml,
39
+ pageContext: {},
40
+ };
41
+ }
42
+ else {
43
+ // do nothing: Just exists to signal fastify server that no routes matched and we should proxy
44
+ return {};
45
+ }
46
+ }
@@ -0,0 +1,13 @@
1
+ import route from "@alignable/bifrost/proxy/pages/restorationVisit/route";
2
+ import Page from "@alignable/bifrost/proxy/pages/Page";
3
+ declare const _default: {
4
+ route: typeof route;
5
+ Page: typeof Page;
6
+ meta: {
7
+ onBeforeRender: {
8
+ env: "server-and-client";
9
+ };
10
+ };
11
+ };
12
+ export default _default;
13
+ //# sourceMappingURL=+config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"+config.d.ts","sourceRoot":"","sources":["../../../../proxy/pages/restorationVisit/+config.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,uDAAuD,CAAC;AAC1E,OAAO,IAAI,MAAM,qCAAqC,CAAC;;;;;;;;;;AAEvD,wBAWmB"}
@@ -0,0 +1,14 @@
1
+ import route from "@alignable/bifrost/proxy/pages/restorationVisit/route";
2
+ import Page from "@alignable/bifrost/proxy/pages/Page";
3
+ export default {
4
+ route,
5
+ Page,
6
+ meta: {
7
+ onBeforeRender: {
8
+ // We tell vite-plugin-ssr to load and execute onBeforeRender()
9
+ // not only on the server-side but also on the client-side.
10
+ // Moving onBeforeRender to client tells VPS it does not need to make network request on navigation
11
+ env: "server-and-client",
12
+ },
13
+ },
14
+ };
@@ -0,0 +1,2 @@
1
+ export default function route(): boolean;
2
+ //# sourceMappingURL=route.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../../../proxy/pages/restorationVisit/route.ts"],"names":[],"mappings":"AACA,MAAM,CAAC,OAAO,UAAU,KAAK,YAE5B"}
@@ -0,0 +1,4 @@
1
+ // never matches - see onBeforeRoute for how this route only triggers on restoration visit.
2
+ export default function route() {
3
+ return false;
4
+ }
@@ -0,0 +1,24 @@
1
+ import onRenderClient from "@alignable/bifrost/renderer/onRenderClient";
2
+ import onRenderHtml from "@alignable/bifrost/renderer/onRenderHtml";
3
+ import onBeforeRoute from "@alignable/bifrost/renderer/onBeforeRoute";
4
+ declare const _default: {
5
+ passToClient: string[];
6
+ onRenderClient: typeof onRenderClient;
7
+ onRenderHtml: typeof onRenderHtml;
8
+ onBeforeRoute: typeof onBeforeRoute;
9
+ clientRouting: true;
10
+ hydrationCanBeAborted: true;
11
+ meta: {
12
+ Layout: {
13
+ env: "server-and-client";
14
+ };
15
+ layoutProps: {
16
+ env: "server-and-client";
17
+ };
18
+ documentProps: {
19
+ env: "server-and-client";
20
+ };
21
+ };
22
+ };
23
+ export default _default;
24
+ //# sourceMappingURL=+config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"+config.d.ts","sourceRoot":"","sources":["../../renderer/+config.ts"],"names":[],"mappings":"AACA,OAAO,cAAc,MAAM,4CAA4C,CAAC;AACxE,OAAO,YAAY,MAAM,0CAA0C,CAAC;AACpE,OAAO,aAAa,MAAM,2CAA2C,CAAC;;;;;;;;;;;;;;;;;;;;AAEtE,wBAcmB"}
@@ -0,0 +1,18 @@
1
+ import onRenderClient from "@alignable/bifrost/renderer/onRenderClient";
2
+ import onRenderHtml from "@alignable/bifrost/renderer/onRenderHtml";
3
+ import onBeforeRoute from "@alignable/bifrost/renderer/onBeforeRoute";
4
+ export default {
5
+ passToClient: [
6
+ "layoutProps", "pageProps", "redirectTo", "documentProps",
7
+ ],
8
+ onRenderClient,
9
+ onRenderHtml,
10
+ onBeforeRoute,
11
+ clientRouting: true,
12
+ hydrationCanBeAborted: true,
13
+ meta: {
14
+ Layout: { env: "server-and-client" },
15
+ layoutProps: { env: "server-and-client" },
16
+ documentProps: { env: "server-and-client" },
17
+ },
18
+ };
@@ -0,0 +1,7 @@
1
+ /// <reference types="react" />
2
+ export default Page;
3
+ declare function Page({ is404, errorInfo }: {
4
+ is404: boolean;
5
+ errorInfo?: string;
6
+ }): JSX.Element;
7
+ //# sourceMappingURL=Page.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Page.d.ts","sourceRoot":"","sources":["../../../renderer/_error/Page.tsx"],"names":[],"mappings":";AAAA,eAAe,IAAI,CAAC;AAIpB,iBAAS,IAAI,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,eAiBzE"}
@@ -0,0 +1,15 @@
1
+ export default Page;
2
+ import React from "react";
3
+ function Page({ is404, errorInfo }) {
4
+ if (is404) {
5
+ return (React.createElement(React.Fragment, null,
6
+ React.createElement("h1", null, "404 Page Not Found"),
7
+ React.createElement("p", null, "This page could not be found."),
8
+ React.createElement("p", null, errorInfo)));
9
+ }
10
+ else {
11
+ return (React.createElement(React.Fragment, null,
12
+ React.createElement("h1", null, "500 Internal Server Error"),
13
+ React.createElement("p", null, "Something went wrong.")));
14
+ }
15
+ }
@@ -0,0 +1,3 @@
1
+ import { PageContextNoProxy } from "../types/internal";
2
+ export declare function getDocumentProps(pageContext: PageContextNoProxy): import("../types/internal").DocumentProps;
3
+ //# sourceMappingURL=getDocumentProps.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getDocumentProps.d.ts","sourceRoot":"","sources":["../../renderer/getDocumentProps.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAEvD,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,kBAAkB,6CAE/D"}
@@ -0,0 +1,3 @@
1
+ export function getDocumentProps(pageContext) {
2
+ return pageContext.config.documentProps || pageContext.documentProps || {};
3
+ }
@@ -0,0 +1,9 @@
1
+ export default function onBeforeRoute(_pageContext: any): {
2
+ pageContext: {
3
+ _pageId: string;
4
+ proxySendClient?: import("../types/internal").Proxy | undefined;
5
+ layout: string;
6
+ layoutProps: Record<string, unknown>;
7
+ };
8
+ } | undefined;
9
+ //# sourceMappingURL=onBeforeRoute.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"onBeforeRoute.d.ts","sourceRoot":"","sources":["../../renderer/onBeforeRoute.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,OAAO,UAAU,aAAa,CAAC,YAAY,EAAE,GAAG;;;;;;;cAYtD"}
@@ -0,0 +1,15 @@
1
+ import { getSnapshot } from "../lib/snapshots";
2
+ export default function onBeforeRoute(_pageContext) {
3
+ const snapshot = getSnapshot();
4
+ if (!!snapshot?.proxySendClient) {
5
+ return {
6
+ pageContext: {
7
+ ...snapshot,
8
+ _pageId: "/proxy/pages/restorationVisit",
9
+ },
10
+ };
11
+ }
12
+ else {
13
+ return undefined;
14
+ }
15
+ }
@@ -0,0 +1,4 @@
1
+ import { PageContextNoProxyClient } from "../types/internal";
2
+ import "../../lib/turbolinks";
3
+ export default function onRenderClient(pageContext: PageContextNoProxyClient): Promise<void>;
4
+ //# sourceMappingURL=onRenderClient.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"onRenderClient.d.ts","sourceRoot":"","sources":["../../renderer/onRenderClient.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAM7D,OAAO,sBAAsB,CAAC;AAE9B,wBAA8B,cAAc,CAC1C,WAAW,EAAE,wBAAwB,iBA8BtC"}
@@ -0,0 +1,29 @@
1
+ import React from "react";
2
+ import { renderReact } from "../lib/renderReact";
3
+ import { PageShell } from "../lib/PageShell";
4
+ import { turbolinksClickListener } from "../lib/linkInterceptor";
5
+ import { getDocumentProps } from "./getDocumentProps";
6
+ import { cacheProxiedBody } from "../lib/snapshots";
7
+ import { navigateAnywhere } from "../lib/navigateAnywhere";
8
+ import "../../lib/turbolinks";
9
+ export default async function onRenderClient(pageContext) {
10
+ if (navigateAnywhere(pageContext.redirectTo))
11
+ return;
12
+ const { Page, pageProps } = pageContext;
13
+ const { Layout, layoutProps } = pageContext.config;
14
+ if (!Page)
15
+ throw new Error("Client-side render() hook expects Page to be exported");
16
+ if (!Layout)
17
+ throw new Error("Client-side render() hook expects Layout to be exported");
18
+ document.removeEventListener("click", turbolinksClickListener);
19
+ cacheProxiedBody();
20
+ const { title = "", description = "" } = getDocumentProps(pageContext);
21
+ document.title = title;
22
+ document.head
23
+ .querySelector("meta[name='description']")
24
+ ?.setAttribute("content", description);
25
+ const page = (React.createElement(PageShell, { pageContext: pageContext },
26
+ React.createElement(Layout, { ...layoutProps },
27
+ React.createElement(Page, { ...pageProps }))));
28
+ renderReact(page, pageContext.isHydration);
29
+ }
@@ -0,0 +1,6 @@
1
+ import { PageContextNoProxyServer } from "../types/internal";
2
+ export default function onRenderHtml(pageContext: PageContextNoProxyServer): Promise<{
3
+ documentHtml: import("vite-plugin-ssr/dist/types/node/runtime/html/renderHtml").TemplateWrapped;
4
+ pageContext: {};
5
+ }>;
6
+ //# sourceMappingURL=onRenderHtml.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"onRenderHtml.d.ts","sourceRoot":"","sources":["../../renderer/onRenderHtml.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAG7D,wBAA8B,YAAY,CACxC,WAAW,EAAE,wBAAwB;;;GA0CtC"}
@@ -0,0 +1,38 @@
1
+ import ReactDOMServer from "react-dom/server";
2
+ import React from "react";
3
+ import { PageShell } from "../lib/PageShell";
4
+ import { escapeInject, dangerouslySkipEscape } from "vite-plugin-ssr/server";
5
+ import { getDocumentProps } from "./getDocumentProps";
6
+ export default async function onRenderHtml(pageContext) {
7
+ const { Page, pageProps } = pageContext;
8
+ const { Layout, layoutProps } = pageContext.config;
9
+ if (!Page)
10
+ throw new Error("Server-side render() hook expects Page to be exported");
11
+ if (!Layout)
12
+ throw new Error("Server-side render() hook expects Layout to be exported");
13
+ const pageHtml = ReactDOMServer.renderToString(React.createElement(PageShell, { pageContext: pageContext },
14
+ React.createElement(Layout, { ...layoutProps },
15
+ React.createElement(Page, { ...pageProps }))));
16
+ // // See https://vite-plugin-ssr.com/head
17
+ const { title = "", description = "" } = getDocumentProps(pageContext);
18
+ if (!title) {
19
+ console.warn(`No title set for ${pageContext.urlOriginal}!`);
20
+ }
21
+ const documentHtml = escapeInject `<!DOCTYPE html>
22
+ <html lang="en">
23
+ <head>
24
+ <title>${title}</title>
25
+ <meta name="title" property="og:title" content="${title}"/>
26
+ <meta name="description" content="${description}"/>
27
+ </head>
28
+ <body>
29
+ <div id="page-view">${dangerouslySkipEscape(pageHtml)}</div>
30
+ </body>
31
+ </html>`;
32
+ return {
33
+ documentHtml,
34
+ pageContext: {
35
+ // We can add some `pageContext` here, which is useful if we want to do page redirection https://vite-plugin-ssr.com/page-redirection
36
+ },
37
+ };
38
+ }
@@ -0,0 +1,10 @@
1
+ import React from 'react';
2
+ import { PageContext } from "../types/internal";
3
+ export { PageContextProvider };
4
+ export { usePageContext };
5
+ declare function PageContextProvider({ pageContext, children }: {
6
+ pageContext: PageContext;
7
+ children: React.ReactNode;
8
+ }): JSX.Element;
9
+ declare function usePageContext(): PageContext;
10
+ //# sourceMappingURL=usePageContext.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usePageContext.d.ts","sourceRoot":"","sources":["../../renderer/usePageContext.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAqB,MAAM,OAAO,CAAA;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD,OAAO,EAAE,mBAAmB,EAAE,CAAA;AAC9B,OAAO,EAAE,cAAc,EAAE,CAAA;AAIzB,iBAAS,mBAAmB,CAAC,EAAE,WAAW,EAAE,QAAQ,EAAE,EAAE;IAAE,WAAW,EAAE,WAAW,CAAC;IAAC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAAE,eAE9G;AAED,iBAAS,cAAc,gBAGtB"}
@@ -0,0 +1,13 @@
1
+ // `usePageContext` allows us to access `pageContext` in any React component.
2
+ // See https://vite-plugin-ssr.com/pageContext-anywhere
3
+ import React, { useContext } from 'react';
4
+ export { PageContextProvider };
5
+ export { usePageContext };
6
+ const Context = React.createContext(undefined);
7
+ function PageContextProvider({ pageContext, children }) {
8
+ return React.createElement(Context.Provider, { value: pageContext }, children);
9
+ }
10
+ function usePageContext() {
11
+ const pageContext = useContext(Context);
12
+ return pageContext;
13
+ }
@@ -0,0 +1,52 @@
1
+ import { PropsWithChildren } from "react";
2
+ import { PageContextBuiltIn, PageContextBuiltInClientWithClientRouting as PageContextBuiltInClient } from "vite-plugin-ssr/types";
3
+ export interface Proxy {
4
+ body: string;
5
+ head: string;
6
+ bodyAttrs: Record<string, string>;
7
+ }
8
+ export type Layout<LayoutProps> = React.ComponentType<PropsWithChildren<LayoutProps>>;
9
+ export type LayoutMap<LayoutProps> = Record<string, Layout<LayoutProps>>;
10
+ type PageContextProxyCommon<LayoutProps = Record<string, unknown>> = {
11
+ layout: string;
12
+ layoutProps: LayoutProps;
13
+ config: {
14
+ layoutMap: LayoutMap<LayoutProps>;
15
+ };
16
+ };
17
+ type PageContextProxyClientHydration = {
18
+ isHydration: true;
19
+ redirectTo?: string;
20
+ };
21
+ type PageContextProxyClientNav = {
22
+ isHydration: false;
23
+ redirectTo?: string;
24
+ proxySendClient?: Proxy;
25
+ };
26
+ export type PageContextProxyServer = PageContextBuiltIn<Page> & PageContextProxyCommon & {
27
+ proxy: Proxy;
28
+ };
29
+ export type PageContextProxyClient = PageContextBuiltInClient<Page> & PageContextProxyCommon & (PageContextProxyClientHydration | PageContextProxyClientNav);
30
+ export type PageContextProxy = PageContextProxyServer | PageContextProxyClient;
31
+ export interface DocumentProps {
32
+ title?: string;
33
+ description?: string;
34
+ }
35
+ type PageProps = Record<string, unknown>;
36
+ type Page = React.ComponentType<PageProps>;
37
+ interface PageContextNoProxyCommon<LayoutProps = Record<string, unknown>> {
38
+ pageProps: PageProps;
39
+ redirectTo?: string;
40
+ documentProps?: DocumentProps;
41
+ config: {
42
+ Layout: Layout<LayoutProps>;
43
+ layoutProps?: LayoutProps;
44
+ documentProps?: DocumentProps;
45
+ };
46
+ }
47
+ export type PageContextNoProxyServer = PageContextBuiltIn<Page> & PageContextNoProxyCommon;
48
+ export type PageContextNoProxyClient = PageContextBuiltInClient<Page> & PageContextNoProxyCommon;
49
+ export type PageContextNoProxy = PageContextNoProxyServer | PageContextNoProxyClient;
50
+ export type PageContext = PageContextNoProxy | PageContextProxy;
51
+ export {};
52
+ //# sourceMappingURL=internal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"internal.d.ts","sourceRoot":"","sources":["../../types/internal.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,OAAO,CAAC;AAC1C,OAAO,EACL,kBAAkB,EAClB,yCAAyC,IAAI,wBAAwB,EACtE,MAAM,uBAAuB,CAAC;AAI/B,MAAM,WAAW,KAAK;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACnC;AAED,MAAM,MAAM,MAAM,CAAC,WAAW,IAAI,KAAK,CAAC,aAAa,CAAC,iBAAiB,CAAC,WAAW,CAAC,CAAC,CAAC;AACtF,MAAM,MAAM,SAAS,CAAC,WAAW,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC;AAEzE,KAAK,sBAAsB,CAAC,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI;IAEnE,MAAM,EAAE,MAAM,CAAC;IAEf,WAAW,EAAE,WAAW,CAAC;IACzB,MAAM,EAAE;QACN,SAAS,EAAE,SAAS,CAAC,WAAW,CAAC,CAAC;KACnC,CAAC;CACH,CAAC;AAEF,KAAK,+BAA+B,GAAG;IACrC,WAAW,EAAE,IAAI,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,KAAK,yBAAyB,GAAG;IAC/B,WAAW,EAAE,KAAK,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IAGpB,eAAe,CAAC,EAAE,KAAK,CAAC;CACzB,CAAC;AACF,MAAM,MAAM,sBAAsB,GAAG,kBAAkB,CAAC,IAAI,CAAC,GAC3D,sBAAsB,GAAG;IAAE,KAAK,EAAE,KAAK,CAAA;CAAE,CAAC;AAC5C,MAAM,MAAM,sBAAsB,GAAG,wBAAwB,CAAC,IAAI,CAAC,GACjE,sBAAsB,GACtB,CAAC,+BAA+B,GAAG,yBAAyB,CAAC,CAAC;AAEhE,MAAM,MAAM,gBAAgB,GAAG,sBAAsB,GAAG,sBAAsB,CAAC;AAK/E,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,KAAK,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AACzC,KAAK,IAAI,GAAG,KAAK,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC;AAE3C,UAAU,wBAAwB,CAAC,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IACtE,SAAS,EAAE,SAAS,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,MAAM,EAAE;QACN,MAAM,EAAE,MAAM,CAAC,WAAW,CAAC,CAAC;QAC5B,WAAW,CAAC,EAAE,WAAW,CAAC;QAC1B,aAAa,CAAC,EAAE,aAAa,CAAC;KAC/B,CAAC;CACH;AAED,MAAM,MAAM,wBAAwB,GAAG,kBAAkB,CAAC,IAAI,CAAC,GAC7D,wBAAwB,CAAC;AAC3B,MAAM,MAAM,wBAAwB,GAAG,wBAAwB,CAAC,IAAI,CAAC,GACnE,wBAAwB,CAAC;AAE3B,MAAM,MAAM,kBAAkB,GAC1B,wBAAwB,GACxB,wBAAwB,CAAC;AAE7B,MAAM,MAAM,WAAW,GAAG,kBAAkB,GAAG,gBAAgB,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "@alignable/bifrost",
3
+ "repository": "https://github.com/Alignable/bifrost.git",
4
+ "version": "0.0.2",
5
+ "type": "module",
6
+ "types": "./dist/index.d.ts",
7
+ "exports": {
8
+ "./renderer/+config": "./dist/renderer/+config.js",
9
+ "./renderer/onRenderClient": "./dist/renderer/onRenderClient.js",
10
+ "./renderer/onRenderHtml": "./dist/renderer/onRenderHtml.js",
11
+ "./renderer/onBeforeRoute": "./dist/renderer/onBeforeRoute.js",
12
+ "./proxy/pages/+config": "./dist/proxy/pages/+config.js",
13
+ "./proxy/pages/onRenderClient": "./dist/proxy/pages/onRenderClient.js",
14
+ "./proxy/pages/onRenderHtml": "./dist/proxy/pages/onRenderHtml.js",
15
+ "./proxy/pages/Page": "./dist/proxy/pages/Page.js",
16
+ "./proxy/pages/onBeforeRender": "./dist/proxy/pages/onBeforeRender.js",
17
+ "./proxy/pages/restorationVisit/+config": "./dist/proxy/pages/restorationVisit/+config.js",
18
+ "./proxy/pages/restorationVisit/route": "./dist/proxy/pages/restorationVisit/route.js",
19
+ "./package.json": "./package.json",
20
+ ".": "./dist/index.js"
21
+ },
22
+ "scripts": {
23
+ "dev": "vite",
24
+ "release": "release-me patch",
25
+ "build": "rm -rf dist/ && yarn tsc"
26
+ },
27
+ "files": [
28
+ "dist/"
29
+ ],
30
+ "dependencies": {
31
+ "cross-env": "^7.0.3",
32
+ "react": "^18.x.x",
33
+ "react-dom": "^18.x.x",
34
+ "uuid": "^9.0.0",
35
+ "vite-plugin-ssr": "0.4.125"
36
+ },
37
+ "peerDependencies": {
38
+ "react": "^18.x.x",
39
+ "react-dom": "^18.x.x",
40
+ "vite-plugin-ssr": "0.4.125"
41
+ },
42
+ "devDependencies": {
43
+ "@types/node": "^18.11.9",
44
+ "@types/react": "^18.0.8",
45
+ "@types/react-dom": "^18.0.3",
46
+ "@vitejs/plugin-react": "^3.0.0",
47
+ "turbolinks": "5.3.0-beta.1",
48
+ "typescript": "^5.0.4",
49
+ "vite": "^4.0.3"
50
+ }
51
+ }