eddev 0.2.8 → 0.2.11

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.
@@ -31,7 +31,39 @@ var blockAttributes_1 = require("./blockAttributes");
31
31
  var react_1 = require("react");
32
32
  var ErrorBoundaryFrontend_1 = require("./ErrorBoundaryFrontend");
33
33
  exports.BlocksContext = (0, react_1.createContext)(undefined);
34
+ function wrapPromise(promise) {
35
+ var status = "pending";
36
+ var result;
37
+ var suspender = promise.then(function (r) {
38
+ status = "success";
39
+ result = r;
40
+ }, function (e) {
41
+ status = "error";
42
+ result = e;
43
+ });
44
+ return {
45
+ read: function () {
46
+ //console.log(status);
47
+ if (status === "pending") {
48
+ throw suspender;
49
+ }
50
+ else if (status === "error") {
51
+ throw result;
52
+ }
53
+ else if (status === "success") {
54
+ return result;
55
+ }
56
+ },
57
+ };
58
+ }
59
+ var blockManifestResource = null;
34
60
  function ContentBlocks(props) {
61
+ var blockTypes = blocks_1.default;
62
+ if (blocks_1.default.then && process.serverless && !blocks_1.default.default) {
63
+ if (!blockManifestResource)
64
+ blockManifestResource = wrapPromise(blocks_1.default);
65
+ blockTypes = blockManifestResource.read().default;
66
+ }
35
67
  if (process.admin) {
36
68
  throw new Error("ContentBlocks should only be used on the frontend.");
37
69
  }
@@ -44,8 +76,8 @@ function ContentBlocks(props) {
44
76
  var ctx = __assign(__assign({}, parentContext), { ancestors: __spreadArray(__spreadArray([], ((parentContext === null || parentContext === void 0 ? void 0 : parentContext.ancestors) || []), true), [parentContext === null || parentContext === void 0 ? void 0 : parentContext.current], false).filter(Boolean), parent: parentContext === null || parentContext === void 0 ? void 0 : parentContext.current, current: block, prev: props.blocks[index - 1], next: props.blocks[index + 1] });
45
77
  // Figure out the
46
78
  var blockNode;
47
- if (block.blockName in blocks_1.default) {
48
- var Component = blocks_1.default[block.blockName];
79
+ if (block.blockName in blockTypes) {
80
+ var Component = blockTypes[block.blockName];
49
81
  if (!Component)
50
82
  return (0, jsx_runtime_1.jsx)(react_1.Fragment, {}, void 0);
51
83
  blockNode = ((0, jsx_runtime_1.jsx)(blockAttributes_1.InlineEditingContextProvider, __assign({ block: [block.blockName, block.props], values: block.inline, innerBlocks: block.innerBlocks }, { children: (0, jsx_runtime_1.jsx)(Component, __assign({}, block.props, { innerHTML: block.innerHTML,
@@ -15,10 +15,21 @@ exports.NextRouter = void 0;
15
15
  var jsx_runtime_1 = require("react/jsx-runtime");
16
16
  var routing_1 = require("../routing");
17
17
  var router_1 = require("next/router");
18
+ var react_1 = require("react");
19
+ var hooks_1 = require("../hooks");
18
20
  function NextRouter(_a) {
19
21
  var children = _a.children, path = _a.path, data = _a.data;
20
22
  var nextRoute = (0, router_1.useRouter)();
23
+ var setIsLoading = (0, hooks_1.usePageLoad)(function (s) { return s.setIsLoading; });
21
24
  var route = __assign(__assign({}, nextRoute), { pathname: nextRoute.asPath });
25
+ (0, react_1.useEffect)(function () {
26
+ router_1.Router.events.on("routeChangeStart", function () {
27
+ console.log("Loading");
28
+ setIsLoading(true);
29
+ });
30
+ router_1.Router.events.on("routeChangeStart", function () { return setIsLoading(false); });
31
+ router_1.Router.events.on("routeChangeError", function () { return setIsLoading(false); });
32
+ }, []);
22
33
  return ((0, jsx_runtime_1.jsx)(routing_1.RouterRoot, __assign({ url: nextRoute.asPath, data: data, onNavigateRequest: function (url) {
23
34
  route.push(url);
24
35
  // setPendingUrl({ popped: false, url })
@@ -9,47 +9,75 @@ export declare const EDConfigSchema: z.ZodObject<{
9
9
  themeAssets: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
10
10
  apiOnly: z.ZodOptional<z.ZodBoolean>;
11
11
  endpoints: z.ZodRecord<z.ZodString, z.ZodString>;
12
+ defaultRevalidate: z.ZodOptional<z.ZodNumber>;
13
+ defaultRevalidateQueries: z.ZodOptional<z.ZodNumber>;
12
14
  }, "strip", z.ZodTypeAny, {
13
15
  themeAssets?: string[] | undefined;
14
16
  apiOnly?: boolean | undefined;
17
+ defaultRevalidate?: number | undefined;
18
+ defaultRevalidateQueries?: number | undefined;
15
19
  enabled: boolean;
16
20
  uploads: "proxy" | "remote";
17
21
  plugins: "proxy" | "remote";
18
- theme: "copy" | "proxy" | "remote";
22
+ theme: "proxy" | "remote" | "copy";
19
23
  endpoints: Record<string, string>;
20
24
  }, {
21
25
  themeAssets?: string[] | undefined;
22
26
  apiOnly?: boolean | undefined;
27
+ defaultRevalidate?: number | undefined;
28
+ defaultRevalidateQueries?: number | undefined;
23
29
  enabled: boolean;
24
30
  uploads: "proxy" | "remote";
25
31
  plugins: "proxy" | "remote";
26
- theme: "copy" | "proxy" | "remote";
32
+ theme: "proxy" | "remote" | "copy";
27
33
  endpoints: Record<string, string>;
28
34
  }>>;
35
+ cache: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
36
+ props: z.ZodNumber;
37
+ queries: z.ZodNumber;
38
+ }, "strip", z.ZodTypeAny, {
39
+ props: number;
40
+ queries: number;
41
+ }, {
42
+ props: number;
43
+ queries: number;
44
+ }>>>;
29
45
  devUI: z.ZodEnum<["disabled", "enabled"]>;
30
46
  }, "strip", z.ZodTypeAny, {
31
47
  $schema?: string | undefined;
32
48
  serverless?: {
33
49
  themeAssets?: string[] | undefined;
34
50
  apiOnly?: boolean | undefined;
51
+ defaultRevalidate?: number | undefined;
52
+ defaultRevalidateQueries?: number | undefined;
35
53
  enabled: boolean;
36
54
  uploads: "proxy" | "remote";
37
55
  plugins: "proxy" | "remote";
38
- theme: "copy" | "proxy" | "remote";
56
+ theme: "proxy" | "remote" | "copy";
39
57
  endpoints: Record<string, string>;
40
58
  } | undefined;
59
+ cache?: Record<string, {
60
+ props: number;
61
+ queries: number;
62
+ }> | undefined;
41
63
  devUI: "disabled" | "enabled";
42
64
  }, {
43
65
  $schema?: string | undefined;
44
66
  serverless?: {
45
67
  themeAssets?: string[] | undefined;
46
68
  apiOnly?: boolean | undefined;
69
+ defaultRevalidate?: number | undefined;
70
+ defaultRevalidateQueries?: number | undefined;
47
71
  enabled: boolean;
48
72
  uploads: "proxy" | "remote";
49
73
  plugins: "proxy" | "remote";
50
- theme: "copy" | "proxy" | "remote";
74
+ theme: "proxy" | "remote" | "copy";
51
75
  endpoints: Record<string, string>;
52
76
  } | undefined;
77
+ cache?: Record<string, {
78
+ props: number;
79
+ queries: number;
80
+ }> | undefined;
53
81
  devUI: "disabled" | "enabled";
54
82
  }>;
55
83
  export declare type EDConfig = z.infer<typeof EDConfigSchema>;
@@ -13,7 +13,15 @@ exports.EDConfigSchema = zod_1.z.object({
13
13
  themeAssets: zod_1.z.array(zod_1.z.string()).optional(),
14
14
  apiOnly: zod_1.z.boolean().optional(),
15
15
  endpoints: zod_1.z.record(zod_1.z.string(), zod_1.z.string()),
16
+ defaultRevalidate: zod_1.z.number().optional(),
17
+ defaultRevalidateQueries: zod_1.z.number().optional(),
16
18
  })
17
19
  .optional(),
20
+ cache: zod_1.z
21
+ .record(zod_1.z.string(), zod_1.z.object({
22
+ props: zod_1.z.number(),
23
+ queries: zod_1.z.number(),
24
+ }))
25
+ .optional(),
18
26
  devUI: zod_1.z.enum(["disabled", "enabled"]),
19
27
  });
@@ -3,24 +3,36 @@ export declare function getEDConfig(dir?: string): import("zod").SafeParseReturn
3
3
  serverless?: {
4
4
  themeAssets?: string[] | undefined;
5
5
  apiOnly?: boolean | undefined;
6
+ defaultRevalidate?: number | undefined;
7
+ defaultRevalidateQueries?: number | undefined;
6
8
  enabled: boolean;
7
9
  uploads: "proxy" | "remote";
8
10
  plugins: "proxy" | "remote";
9
- theme: "copy" | "proxy" | "remote";
11
+ theme: "proxy" | "remote" | "copy";
10
12
  endpoints: Record<string, string>;
11
13
  } | undefined;
14
+ cache?: Record<string, {
15
+ props: number;
16
+ queries: number;
17
+ }> | undefined;
12
18
  devUI: "disabled" | "enabled";
13
19
  }, {
14
20
  $schema?: string | undefined;
15
21
  serverless?: {
16
22
  themeAssets?: string[] | undefined;
17
23
  apiOnly?: boolean | undefined;
24
+ defaultRevalidate?: number | undefined;
25
+ defaultRevalidateQueries?: number | undefined;
18
26
  enabled: boolean;
19
27
  uploads: "proxy" | "remote";
20
28
  plugins: "proxy" | "remote";
21
- theme: "copy" | "proxy" | "remote";
29
+ theme: "proxy" | "remote" | "copy";
22
30
  endpoints: Record<string, string>;
23
31
  } | undefined;
32
+ cache?: Record<string, {
33
+ props: number;
34
+ queries: number;
35
+ }> | undefined;
24
36
  devUI: "disabled" | "enabled";
25
37
  }>;
26
38
  export declare function getEDConfigUnwrapped(dir?: string): {
@@ -28,12 +40,18 @@ export declare function getEDConfigUnwrapped(dir?: string): {
28
40
  serverless?: {
29
41
  themeAssets?: string[] | undefined;
30
42
  apiOnly?: boolean | undefined;
43
+ defaultRevalidate?: number | undefined;
44
+ defaultRevalidateQueries?: number | undefined;
31
45
  enabled: boolean;
32
46
  uploads: "proxy" | "remote";
33
47
  plugins: "proxy" | "remote";
34
- theme: "copy" | "proxy" | "remote";
48
+ theme: "proxy" | "remote" | "copy";
35
49
  endpoints: Record<string, string>;
36
50
  } | undefined;
51
+ cache?: Record<string, {
52
+ props: number;
53
+ queries: number;
54
+ }> | undefined;
37
55
  devUI: "disabled" | "enabled";
38
56
  };
39
57
  export declare function getEDConfigFile(dir?: string): string;
@@ -3,23 +3,35 @@ export declare function parseConfig(config: any): import("zod").SafeParseReturnT
3
3
  serverless?: {
4
4
  themeAssets?: string[] | undefined;
5
5
  apiOnly?: boolean | undefined;
6
+ defaultRevalidate?: number | undefined;
7
+ defaultRevalidateQueries?: number | undefined;
6
8
  enabled: boolean;
7
9
  uploads: "proxy" | "remote";
8
10
  plugins: "proxy" | "remote";
9
- theme: "copy" | "proxy" | "remote";
11
+ theme: "proxy" | "remote" | "copy";
10
12
  endpoints: Record<string, string>;
11
13
  } | undefined;
14
+ cache?: Record<string, {
15
+ props: number;
16
+ queries: number;
17
+ }> | undefined;
12
18
  devUI: "disabled" | "enabled";
13
19
  }, {
14
20
  $schema?: string | undefined;
15
21
  serverless?: {
16
22
  themeAssets?: string[] | undefined;
17
23
  apiOnly?: boolean | undefined;
24
+ defaultRevalidate?: number | undefined;
25
+ defaultRevalidateQueries?: number | undefined;
18
26
  enabled: boolean;
19
27
  uploads: "proxy" | "remote";
20
28
  plugins: "proxy" | "remote";
21
- theme: "copy" | "proxy" | "remote";
29
+ theme: "proxy" | "remote" | "copy";
22
30
  endpoints: Record<string, string>;
23
31
  } | undefined;
32
+ cache?: Record<string, {
33
+ props: number;
34
+ queries: number;
35
+ }> | undefined;
24
36
  devUI: "disabled" | "enabled";
25
37
  }>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eddev",
3
- "version": "0.2.8",
3
+ "version": "0.2.11",
4
4
  "main": "./index.js",
5
5
  "license": "MIT",
6
6
  "bin": {
@@ -329,7 +329,7 @@ exports.Link = (0, react_1.forwardRef)(function (props, ref) {
329
329
  // @ts-ignore
330
330
  if (process.serverless) {
331
331
  var NextLink = require("next/link").default;
332
- return ((0, jsx_runtime_1.jsx)(NextLink, __assign({ href: props.href, passHref: true }, { children: (0, jsx_runtime_1.jsx)("a", __assign({ ref: ref }, props, { href: undefined }), void 0) }), void 0));
332
+ return ((0, jsx_runtime_1.jsx)(NextLink, __assign({ href: props.href, passHref: true, prefetch: false }, { children: (0, jsx_runtime_1.jsx)("a", __assign({ ref: ref }, props, { href: undefined }), void 0) }), void 0));
333
333
  }
334
334
  var localRef = (0, react_1.useRef)();
335
335
  var router = (0, react_1.useContext)(RouterContext);
@@ -8,12 +8,16 @@ export async function fetchWordpressProps(pathname: string) {
8
8
  const origin = (process.env.SITE_URL as string).replace(/\/$/, "")
9
9
  pathname = pathname.replace(/(^\/|\/$)/g, "")
10
10
  const propsURL = origin + ("/" + pathname + "/?_props=all").replace(/\/+/, "/")
11
+ console.log("Fetching from", propsURL)
11
12
 
12
13
  // Make the request
13
- let response = await fetchWP(propsURL, {})
14
+ let response = await fetchWP(propsURL, {}, async (response) => ({
15
+ text: await response.text(),
16
+ status: response.status,
17
+ }))
14
18
 
15
19
  // Convert to text, rather than JSON — so we can do find-and-replace
16
- let text = await response.text()
20
+ let text = response.text
17
21
 
18
22
  // Convert absolute site URL details to relative paths
19
23
  text = text.replace(new RegExp(origin.replace(/(http|https)/, `https?`) + "([a-z0-9-_./]+)", "g"), (url) => {
@@ -1,17 +1,35 @@
1
1
  import { Agent } from "https"
2
2
  import { fetch } from "cross-fetch"
3
+ import { callSWR } from "./swr"
3
4
 
4
5
  // Used to allow self-signed certificates
5
6
  const agent = new Agent({
6
7
  rejectUnauthorized: false,
7
8
  })
8
9
 
9
- export const fetchWP: typeof fetch = async (url, opts) => {
10
- // TODO basic auth via env variable
11
- // https://stackoverflow.com/questions/43842793/basic-authentication-with-fetch
12
- return fetch(url, {
13
- ...opts,
14
- // @ts-ignore
15
- agent: url.includes("https") ? agent : undefined,
16
- })
10
+ export async function fetchWP<T>(url: string, opts: RequestInit, handler: (response: Response) => Promise<T>) {
11
+ const getData = () => {
12
+ // TODO — basic auth via env variable
13
+ // https://stackoverflow.com/questions/43842793/basic-authentication-with-fetch
14
+ return fetch(url, {
15
+ ...opts,
16
+ // @ts-ignore
17
+ agent: url.includes("https") ? agent : undefined,
18
+ })
19
+ }
20
+
21
+ const requestIsGET = !opts || !opts.method || opts.method.toUpperCase() === "GET"
22
+ if (requestIsGET) {
23
+ return callSWR(url as string, async (setExpiry) => {
24
+ const response = await getData()
25
+ const cacheDuration = parseInt(response.headers.get("x-ed-cache-duration") || "") || 0
26
+ setExpiry(cacheDuration)
27
+ console.log(`CACHE for ${cacheDuration}: ${url}`)
28
+ const result = await handler(response)
29
+ return result
30
+ })
31
+ } else {
32
+ const response = await getData()
33
+ return handler(response)
34
+ }
17
35
  }
@@ -0,0 +1,43 @@
1
+ type CacheItem = {
2
+ data: Promise<any>
3
+ expires: Date
4
+ pending: boolean
5
+ }
6
+
7
+ const cache: { [key: string]: CacheItem } = {}
8
+
9
+ export function callSWR<T>(key: string, func: (setExpiry: (duration: number) => void) => Promise<T>): Promise<T> {
10
+ if (cache[key]) {
11
+ if (new Date() < cache[key].expires || cache[key].pending) {
12
+ // Cache is valid
13
+ console.log("VALID")
14
+ return cache[key].data
15
+ } else {
16
+ // Cache has expired - serve old one, but reload in background
17
+ cache[key].pending = true
18
+ console.log("EXPIRED")
19
+ setImmediate(async () => {
20
+ const data = await func((duration) => {
21
+ cache[key].expires = new Date(Date.now() + duration * 1000)
22
+ console.log("EXPIRY -> ", cache[key].expires)
23
+ })
24
+ cache[key].data = Promise.resolve(data)
25
+ cache[key].pending = false
26
+ })
27
+ return cache[key].data
28
+ }
29
+ } else {
30
+ // Not cached at all, user must wait for the cache to populate
31
+ console.log("MISS")
32
+ const item = {
33
+ data: func((duration) => {
34
+ item.expires = new Date(Date.now() + duration * 1000)
35
+ console.log("EXPIRY -> ", item.expires)
36
+ }),
37
+ expires: new Date(Date.now() + 10000),
38
+ pending: false,
39
+ }
40
+ cache[key] = item
41
+ return item.data
42
+ }
43
+ }
@@ -16,6 +16,6 @@
16
16
  "devDependencies": {
17
17
  "@types/react": "17.0.39",
18
18
  "typescript": "4.5.5",
19
- "next": "^12.1.0"
19
+ "next": "^12.1.6"
20
20
  }
21
21
  }
@@ -1,4 +1,5 @@
1
1
  import { GetStaticPathsResult, GetStaticPropsContext, GetStaticPropsResult } from "next"
2
+ import settings from "_utils/ed-config"
2
3
  import { fetchWordpressProps } from "../_utils/fetch-wordpress-props"
3
4
 
4
5
  export default function Home(props: any) {
@@ -8,13 +9,12 @@ export default function Home(props: any) {
8
9
  export async function getStaticPaths(): Promise<GetStaticPathsResult> {
9
10
  return {
10
11
  paths: [],
11
- fallback: true,
12
+ fallback: "blocking",
12
13
  }
13
14
  }
14
15
 
15
16
  export async function getStaticProps({ params }: GetStaticPropsContext): Promise<GetStaticPropsResult<any>> {
16
17
  const result = await fetchWordpressProps((params?.slug as string[]).join("/"))
17
- console.log("RESULT", result)
18
18
  if (result.status === 404) {
19
19
  return {
20
20
  notFound: true,
@@ -27,7 +27,9 @@ export async function getStaticProps({ params }: GetStaticPropsContext): Promise
27
27
  },
28
28
  }
29
29
  }
30
+ const revalidate = result.data.revalidate || settings.serverless?.defaultRevalidate || false
30
31
  return {
31
32
  props: result.data,
33
+ revalidate: revalidate,
32
34
  }
33
35
  }
@@ -8,6 +8,7 @@ import { useRouter } from "next/router"
8
8
  import { DevUILoader } from "eddev/dev-ui/loader"
9
9
  import { PageMeta } from "../_utils/PageMeta"
10
10
  import { withTRPC } from "@trpc/next"
11
+ import { Suspense } from "react"
11
12
 
12
13
  let appData: any
13
14
 
@@ -16,10 +17,6 @@ function Root({ Component, pageProps }: AppProps) {
16
17
 
17
18
  if (!appData) appData = pageProps?.appData?.data
18
19
 
19
- // const appData = useMemo(() => {
20
- // return pageProps?.appData?.data
21
- // }, [])
22
-
23
20
  const viewProps = pageProps?.viewData?.data
24
21
 
25
22
  const View = manifest[pageProps.view || "404"]
@@ -36,7 +33,9 @@ function Root({ Component, pageProps }: AppProps) {
36
33
  {pageProps?.meta?.head && <PageMeta {...pageProps?.meta?.head} />}
37
34
  {pageProps?.meta?.footer && <PageMeta {...pageProps?.meta?.footer} />}
38
35
  {process.devUI ? <DevUILoader /> : null}
39
- <App>{View && <View {...viewProps} />}</App>
36
+ <App>
37
+ <Suspense fallback={null}>{View && <View {...viewProps} />}</Suspense>
38
+ </App>
40
39
  </NextRouter>
41
40
  </ServerlessAppDataProvider>
42
41
  )
@@ -17,7 +17,7 @@ const validProxyPaths = {
17
17
 
18
18
  export default async function (req: any, res: any) {
19
19
  // Ensure that the request is for a proxy path
20
- const proxyPath = validProxyPaths[req.query.method as keyof typeof validProxyPaths]!
20
+ const proxyPath = validProxyPaths[req.query.method[0] as keyof typeof validProxyPaths]!
21
21
 
22
22
  if (!proxyPath) {
23
23
  return res.status(404).json({
@@ -27,14 +27,18 @@ export default async function (req: any, res: any) {
27
27
 
28
28
  const finalPath = proxyPath.path.replace("*", req.query.method.slice(1).join("/"))
29
29
 
30
- const response = await fetchWP(process.env.SITE_URL + finalPath, {
31
- method: proxyPath.method,
32
- headers: {
33
- "Content-Type": "application/json",
30
+ const response = await fetchWP(
31
+ process.env.SITE_URL + finalPath,
32
+ {
33
+ method: proxyPath.method,
34
+ headers: {
35
+ "Content-Type": "application/json",
36
+ },
34
37
  },
35
- })
36
-
37
- const payload = await response.json()
38
+ async (response) => ({
39
+ payload: await response.json(),
40
+ })
41
+ )
38
42
 
39
- res.status(200).json(payload)
43
+ res.status(200).json(response.payload)
40
44
  }