eddev 2.0.0-beta.57 → 2.0.0-beta.59

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 (47) hide show
  1. package/dist/app/entry/spa-root.js +4 -5
  2. package/dist/app/entry/ssr-root-client.js +4 -5
  3. package/dist/app/entry/ssr-root.js +2 -3
  4. package/dist/app/lib/blocks/editor/EditorSupport.js +2 -3
  5. package/dist/app/lib/hooks/queryUtils.d.ts +27 -0
  6. package/dist/app/lib/hooks/queryUtils.js +28 -8
  7. package/dist/app/lib/hooks/useRPC.d.ts +0 -4
  8. package/dist/app/lib/hooks/useRPC.js +1 -8
  9. package/dist/app/lib/internal/finalize-rpc.d.ts +17 -0
  10. package/dist/app/lib/internal/finalize-rpc.js +3 -0
  11. package/dist/app/lib/internal/index.d.ts +1 -0
  12. package/dist/app/lib/internal/index.js +1 -0
  13. package/dist/app/server/index.d.ts +1 -0
  14. package/dist/app/server/index.js +1 -0
  15. package/dist/app/server/proxy-wp-admin.d.ts +1 -2
  16. package/dist/app/server/proxy-wp-admin.js +3 -1
  17. package/dist/app/server/render-ssr-page.d.ts +11 -5
  18. package/dist/app/server/render-ssr-page.js +75 -6
  19. package/dist/app/server/rpc.d.ts +56 -0
  20. package/dist/app/server/rpc.js +18 -0
  21. package/dist/app/server/server-context.d.ts +1 -0
  22. package/dist/app/server/server-context.js +2 -0
  23. package/dist/app/utils/APIProvider.d.ts +2 -0
  24. package/dist/app/utils/APIProvider.js +5 -0
  25. package/dist/app/utils/BlockErrorBoundary.d.ts +1 -1
  26. package/dist/app/utils/BlockErrorBoundary.js +2 -2
  27. package/dist/app/utils/RouteErrorBoundary.d.ts +1 -1
  28. package/dist/app/utils/RouteErrorBoundary.js +2 -2
  29. package/dist/app/utils/query-client.d.ts +2 -0
  30. package/dist/app/utils/query-client.js +5 -1
  31. package/dist/app/utils/trpc-client.d.ts +2 -0
  32. package/dist/app/utils/trpc-client.js +34 -0
  33. package/dist/node/cli/version.d.ts +1 -1
  34. package/dist/node/cli/version.js +1 -1
  35. package/dist/node/compiler/dev-server.js +1 -0
  36. package/dist/node/compiler/get-vite-config.js +1 -1
  37. package/dist/node/compiler/vinxi-app.d.ts +1 -0
  38. package/dist/node/compiler/vinxi-app.js +42 -5
  39. package/dist/node/compiler/vinxi-codegen.js +124 -41
  40. package/dist/node/graphql/graphql-codegen.d.ts +1 -0
  41. package/dist/node/graphql/graphql-codegen.js +42 -1
  42. package/dist/node/project/manifest/routes-manifest.d.ts +20 -0
  43. package/dist/node/project/manifest/routes-manifest.js +74 -0
  44. package/dist/node/project/project.d.ts +2 -0
  45. package/dist/node/project/project.js +3 -0
  46. package/package.json +5 -1
  47. package/types.app.d.ts +2 -0
@@ -1,9 +1,8 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { QueryClientProvider } from "@tanstack/react-query";
3
- import { BrowserRouter } from "../lib/routing/components/BrowserRouter.js";
4
- import { getQueryClient } from "../utils/query-client.js";
5
- import { DevUILoader } from "../lib/devtools/loader.js";
6
2
  import { Suspense } from "react";
3
+ import { DevUILoader } from "../lib/devtools/loader.js";
4
+ import { BrowserRouter } from "../lib/routing/components/BrowserRouter.js";
5
+ import { APIProvider } from "../utils/APIProvider.js";
7
6
  export function SPARoot() {
8
- return (_jsxs(QueryClientProvider, { client: getQueryClient(), children: [_jsx(Suspense, { children: _jsx(BrowserRouter, {}) }), _jsx(DevUILoader, {})] }));
7
+ return (_jsxs(APIProvider, { children: [_jsx(Suspense, { children: _jsx(BrowserRouter, {}) }), _jsx(DevUILoader, {})] }));
9
8
  }
@@ -1,14 +1,13 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { QueryClientProvider } from "@tanstack/react-query";
3
2
  import { Suspense, useEffect, useState } from "react";
3
+ import { useSnapshot } from "valtio";
4
4
  import { DevUILoader } from "../lib/devtools/loader.js";
5
5
  import { BrowserRouter } from "../lib/routing/components/BrowserRouter.js";
6
- import { getQueryClient } from "../utils/query-client.js";
7
- import { MetaTags } from "./MetaTags.js";
8
- import { useSnapshot } from "valtio";
9
6
  import { clientMetaTags } from "../lib/routing/context.js";
7
+ import { APIProvider } from "../utils/APIProvider.js";
8
+ import { MetaTags } from "./MetaTags.js";
10
9
  export function SSRClientRoot(props) {
11
- return (_jsxs("html", { lang: "en", children: [_jsxs("head", { children: [_jsx(DynamicMetaTags, { tags: props.metaTags }), _jsx(Trackers, { position: "head" }), props.assets] }), _jsxs("body", { children: [_jsx(Trackers, { position: "body" }), _jsxs(QueryClientProvider, { client: getQueryClient(), children: [_jsx(Suspense, { children: _jsx(BrowserRouter, {}) }), _jsx(DevUILoader, {})] }), _jsx(Trackers, { position: "footer" })] })] }));
10
+ return (_jsxs("html", { lang: "en", children: [_jsxs("head", { children: [_jsx(DynamicMetaTags, { tags: props.metaTags }), _jsx(Trackers, { position: "head" }), props.assets] }), _jsxs("body", { children: [_jsx(Trackers, { position: "body" }), _jsxs(APIProvider, { children: [_jsx(Suspense, { children: _jsx(BrowserRouter, {}) }), _jsx(DevUILoader, {})] }), _jsx(Trackers, { position: "footer" })] })] }));
12
11
  }
13
12
  function DynamicMetaTags(props) {
14
13
  const dynamicTags = useSnapshot(clientMetaTags).tags;
@@ -1,15 +1,14 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { QueryClientProvider } from "@tanstack/react-query";
3
2
  import { Suspense } from "react";
4
3
  import { SSRRouter } from "../lib/routing/components/SSRRouter.js";
5
4
  import { getRouteMeta, normalizeRoute } from "../lib/routing/utils.js";
6
- import { getQueryClient } from "../utils/query-client.js";
5
+ import { APIProvider } from "../utils/APIProvider.js";
7
6
  import { MetaTags } from "./MetaTags.js";
8
7
  export function SSRRoot(props) {
9
8
  const loader = props.loader;
10
9
  loader.setAppData(props.initialData.appData.data);
11
10
  loader.populateRouteData(props.pathname, props.initialData);
12
- return (_jsxs("html", { lang: "en", children: [_jsxs("head", { children: [_jsx(MetaTags, { tags: props.metaTags }), props.assets] }), _jsx("body", { children: _jsx(QueryClientProvider, { client: getQueryClient(), children: _jsx(Suspense, { children: _jsx(SSRRouter, { loader: loader, route: normalizeRoute({
11
+ return (_jsxs("html", { lang: "en", children: [_jsxs("head", { children: [_jsx(MetaTags, { tags: props.metaTags }), props.assets] }), _jsx("body", { children: _jsx(APIProvider, { children: _jsx(Suspense, { children: _jsx(SSRRouter, { loader: loader, route: normalizeRoute({
13
12
  id: "initial",
14
13
  component: loader.getRouteComponent(props.initialData.view),
15
14
  key: "",
@@ -1,8 +1,7 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- import { QueryClientProvider } from "@tanstack/react-query";
3
2
  import { createContext, Suspense, useContext } from "react";
4
- import { getQueryClient } from "../../../utils/query-client.js";
5
3
  import { blockManifestReader } from "../../internal/read-block-manifest.js";
4
+ import { APIProvider } from "../../../utils/APIProvider.js";
6
5
  import { ErrorBoundaryEditor } from "./ErrorBoundaryEditor.js";
7
6
  export const BlockContext = createContext(undefined);
8
7
  export function EditableBlock({ payload }) {
@@ -15,5 +14,5 @@ export function EditableBlock({ payload }) {
15
14
  const BlockComponent = getBlock();
16
15
  if (!BlockComponent)
17
16
  return _jsx("div", { children: "Unable to load block component" });
18
- return (_jsx(ErrorBoundaryEditor, { children: _jsx(QueryClientProvider, { client: getQueryClient(), children: _jsx(Suspense, { children: _jsx(BlockComponent, { ...payload }) }) }) }));
17
+ return (_jsx(ErrorBoundaryEditor, { children: _jsx(APIProvider, { children: _jsx(Suspense, { children: _jsx(BlockComponent, { ...payload }) }) }) }));
19
18
  }
@@ -1,4 +1,5 @@
1
1
  import { FetchQueryOptions, UndefinedInitialDataInfiniteOptions, UndefinedInitialDataOptions, UseInfiniteQueryResult, UseMutationOptions, UseMutationResult, UseQueryResult } from "@tanstack/react-query";
2
+ import { TRPCClientError } from "@trpc/client";
2
3
  type OptionalMaybes<T> = T extends any[] ? T : T extends {
3
4
  [key: string]: any;
4
5
  } ? {
@@ -53,4 +54,30 @@ export type UseMutationFunction<TData, TArgs> = ((options?: Omit<UseMutationOpti
53
54
  }) => Promise<TData>;
54
55
  };
55
56
  export declare function createUseMutation<TData extends any, TArgs extends MaybeVars>(init: CreateUseQueryOptions): UseMutationFunction<TData, TArgs>;
57
+ type RPCQueryName = RPCRouter["queries"]["key"];
58
+ type RPCQueryResult<T> = Extract<RPCRouter["queries"], {
59
+ key: T;
60
+ }>["output"];
61
+ type RPCQueryInput<T> = Extract<RPCRouter["queries"], {
62
+ key: T;
63
+ }>["input"];
64
+ type RPCQueryError<T> = TRPCClientError<Extract<RPCRouter["queries"], {
65
+ key: T;
66
+ }>["procedure"]>;
67
+ export declare function useRPCQuery<TName extends RPCQueryName>(key: TName, args: OptionalMaybes<RPCQueryInput<TName>>, options?: Omit<UndefinedInitialDataOptions<RPCQueryResult<TName>, RPCQueryError<TName>, RPCQueryResult<TName>>, "queryKey" | "queryFn"> & {
68
+ headers?: Record<string, string>;
69
+ }): UseQueryResult<RPCQueryResult<TName>, RPCQueryError<TName>>;
70
+ type RPCMutationName = RPCRouter["mutations"]["key"];
71
+ type RPCMutationResult<T> = Extract<RPCRouter["mutations"], {
72
+ key: T;
73
+ }>["output"];
74
+ type RPCMutationInput<T> = Extract<RPCRouter["mutations"], {
75
+ key: T;
76
+ }>["input"];
77
+ type RPCMutationError<T> = TRPCClientError<Extract<RPCRouter["mutations"], {
78
+ key: T;
79
+ }>["procedure"]>;
80
+ export declare function useRPCMutation<TName extends RPCMutationName>(key: TName, options?: Omit<UseMutationOptions<RPCMutationResult<TName>, RPCMutationError<TName>, RPCMutationInput<TName>>, "mutationFn"> & {
81
+ headers?: Record<string, string>;
82
+ }): UseMutationResult<RPCMutationResult<TName>, RPCMutationError<TName>, RPCMutationInput<TName>>;
56
83
  export {};
@@ -2,6 +2,7 @@ import { useInfiniteQuery, useMutation, useQuery, } from "@tanstack/react-query"
2
2
  import { useEffect, useState } from "react";
3
3
  import { joinURL } from "ufo";
4
4
  import { getQueryClient } from "../../utils/query-client.js";
5
+ import { getRPCClient } from "../../utils/trpc-client.js";
5
6
  import { apiConfig } from "../runtime/apiConfig.js";
6
7
  class QueryError extends Error {
7
8
  name = "QueryError";
@@ -52,8 +53,8 @@ export function createUseQuery(init) {
52
53
  const hook = (args, options) => {
53
54
  const customKey = apiConfig.customQueryKey;
54
55
  return useQuery({
55
- queryKey: [init.name, args, options?.headers, options?.headers, customKey],
56
- queryFn: (args) => fetchGETQuery(init.name, args.queryKey[1] ? JSON.stringify(args.queryKey[1]) : "", {
56
+ queryKey: ["query", init.name, args, options?.headers, customKey],
57
+ queryFn: (args) => fetchGETQuery(init.name, args.queryKey[2] ? JSON.stringify(args.queryKey[2]) : "", {
57
58
  headers: options?.headers,
58
59
  }),
59
60
  ...options,
@@ -62,8 +63,8 @@ export function createUseQuery(init) {
62
63
  hook.fetch = async (args, options) => {
63
64
  const customKey = apiConfig.customQueryKey;
64
65
  return getQueryClient().fetchQuery({
65
- queryKey: [init.name, args, options?.headers, options?.headers, customKey],
66
- queryFn: (args) => fetchGETQuery(init.name, args.queryKey[1] ? JSON.stringify(args.queryKey[1]) : "", {
66
+ queryKey: ["query", init.name, args, options?.headers, customKey],
67
+ queryFn: (args) => fetchGETQuery(init.name, args.queryKey[2] ? JSON.stringify(args.queryKey[2]) : "", {
67
68
  headers: options?.headers,
68
69
  }),
69
70
  ...options,
@@ -99,11 +100,11 @@ export function createUseInfiniteQuery(init) {
99
100
  });
100
101
  }, []);
101
102
  return useInfiniteQuery({
102
- queryKey: [init.name, args, init.defaultLimit, options?.headers, options?.headers, customKey],
103
+ queryKey: ["query", init.name, args, init.defaultLimit, options?.headers, customKey],
103
104
  queryFn: async (args) => {
104
105
  const finalArgs = {
105
- limit: args.queryKey[2],
106
- ...(args.queryKey[1] ?? {}),
106
+ limit: args.queryKey[3],
107
+ ...(args.queryKey[2] ?? {}),
107
108
  cursor: args.pageParam,
108
109
  };
109
110
  const data = await fetchGETQuery(init.name, JSON.stringify(finalArgs), {
@@ -181,7 +182,7 @@ const fetchMutation = async (name, params, opts) => {
181
182
  export function createUseMutation(init) {
182
183
  const hook = (options) => {
183
184
  return useMutation({
184
- mutationKey: [init.name],
185
+ mutationKey: ["mutation", init.name],
185
186
  mutationFn: (args) => fetchMutation(init.name, args, {
186
187
  headers: options?.headers,
187
188
  }),
@@ -195,3 +196,22 @@ export function createUseMutation(init) {
195
196
  };
196
197
  return hook;
197
198
  }
199
+ // @ts-ignore
200
+ export function useRPCQuery(key, args, options) {
201
+ return useQuery({
202
+ queryKey: ["rpcQuery", key, args],
203
+ queryFn: async (args) => {
204
+ return getRPCClient().query(key, args.queryKey[2]);
205
+ },
206
+ ...options,
207
+ });
208
+ }
209
+ export function useRPCMutation(key, options) {
210
+ return useMutation({
211
+ mutationKey: ["rpcMutation", key],
212
+ mutationFn: async (args) => {
213
+ return getRPCClient().mutation(key, args);
214
+ },
215
+ ...options,
216
+ });
217
+ }
@@ -1,7 +1,3 @@
1
- export declare const useRPCQuery: RPCUseQuery;
2
- export declare const useRPCMutation: RPCUseMutation;
3
- export declare const useRPCInfiniteQuery: RPCUseInfiniteQuery;
4
- export declare const rpcClient: null;
5
1
  export type UseRPCMutationResult = any;
6
2
  export type UseRPCQueryResult = any;
7
3
  export type UseRPCInfiniteQueryResult = any;
@@ -1,9 +1,2 @@
1
- const trpc = {};
2
- // @ts-ignore
3
- export const useRPCQuery = trpc.useQuery;
4
- // @ts-ignore
5
- export const useRPCMutation = trpc.useMutation;
6
- // @ts-ignore
7
- export const useRPCInfiniteQuery = trpc.useInfiniteQuery;
8
- export const rpcClient = null;
1
+ // const trpc = {}
9
2
  export const RPCClientError = null;
@@ -0,0 +1,17 @@
1
+ import type { AnyTRPCMutationProcedure, AnyTRPCProcedure, AnyTRPCQueryProcedure, AnyTRPCSubscriptionProcedure, inferProcedureInput, inferProcedureOutput } from "@trpc/server";
2
+ type RouterTable = Record<string, Record<string, AnyTRPCProcedure> | AnyTRPCProcedure>;
3
+ type RouterEntry<T extends RouterTable, U extends AnyTRPCProcedure, P extends string = ""> = {
4
+ [K in keyof T]: K extends string ? T[K] extends U ? {
5
+ key: `${P}${K}`;
6
+ input: inferProcedureInput<T[K]>;
7
+ output: inferProcedureOutput<T[K]>;
8
+ procedure: T[K] extends AnyTRPCProcedure ? T[K] : never;
9
+ } : T[K] extends Record<string, U> ? RouterEntry<T[K], U, `${K}.`> : never : never;
10
+ }[keyof T];
11
+ type RouterTypes<T extends RouterTable> = {
12
+ queries: RouterEntry<T, AnyTRPCQueryProcedure>;
13
+ mutations: RouterEntry<T, AnyTRPCMutationProcedure>;
14
+ subscriptions: RouterEntry<T, AnyTRPCSubscriptionProcedure>;
15
+ };
16
+ export declare function finalizeRPCRouter<T extends RouterTable>(router: T): RouterTypes<T>;
17
+ export {};
@@ -0,0 +1,3 @@
1
+ export function finalizeRPCRouter(router) {
2
+ return router;
3
+ }
@@ -2,3 +2,4 @@ export * from "./read-block-manifest.js";
2
2
  export * from "./read-view-manifest.js";
3
3
  export * from "./read-admin-manifest.js";
4
4
  export * from "./internal-store.js";
5
+ export * from "./finalize-rpc.js";
@@ -2,3 +2,4 @@ export * from "./read-block-manifest.js";
2
2
  export * from "./read-view-manifest.js";
3
3
  export * from "./read-admin-manifest.js";
4
4
  export * from "./internal-store.js";
5
+ export * from "./finalize-rpc.js";
@@ -2,3 +2,4 @@ export * from "./render-ssr-page.js";
2
2
  export * from "./server-context.js";
3
3
  export * from "./proxy-wp-admin.js";
4
4
  export * from "./defineRouter.js";
5
+ export * from "./rpc.js";
@@ -2,3 +2,4 @@ export * from "./render-ssr-page.js";
2
2
  export * from "./server-context.js";
3
3
  export * from "./proxy-wp-admin.js";
4
4
  export * from "./defineRouter.js";
5
+ export * from "./rpc.js";
@@ -1,3 +1,2 @@
1
1
  import { EventHandlerRequest, H3Event } from "vinxi/http";
2
- import { ServerContext } from "./server-context.js";
3
- export declare function proxyWpAdmin(event: H3Event<EventHandlerRequest>, serverContext: ServerContext): Promise<Response>;
2
+ export declare function proxyWpAdmin(event: H3Event<EventHandlerRequest>): Promise<Response>;
@@ -1,7 +1,9 @@
1
1
  /// <reference types="vinxi/types/server" />
2
2
  import { splitSetCookieString } from "cookie-es";
3
3
  import { getProxyRequestHeaders, getRequestURL, getWebRequest } from "vinxi/http";
4
- export async function proxyWpAdmin(event, serverContext) {
4
+ import { ServerContext } from "./server-context.js";
5
+ export async function proxyWpAdmin(event) {
6
+ const serverContext = ServerContext.main;
5
7
  const replaceUrls = serverContext.replaceUrls;
6
8
  const req = getWebRequest(event);
7
9
  const proxyUrl = serverContext.getOriginUrl(getRequestURL(event).href);
@@ -1,5 +1,11 @@
1
- import type { RouteData, TrackerTags } from "../lib/routing/types.js";
2
- import { ServerContext } from "./server-context.js";
3
- export declare function renderPageToSSRStream(pathname: string, initialData: RouteData & {
4
- trackers?: TrackerTags;
5
- }, serverContext: ServerContext): Promise<unknown>;
1
+ import type { RouteDataWithTrackers } from "../lib/routing/types.js";
2
+ type SSRArgs = {
3
+ pathname: string;
4
+ initialData: RouteDataWithTrackers;
5
+ };
6
+ export declare function getSsrStream(args: SSRArgs): Promise<ReadableStream<Uint8Array>>;
7
+ type RenderArgs = {
8
+ pathname: string;
9
+ };
10
+ export declare function renderPage(args: RenderArgs): Promise<Response>;
11
+ export {};
@@ -4,10 +4,12 @@ import { Suspense } from "react";
4
4
  import { renderToPipeableStream } from "react-dom/server";
5
5
  import { SSRRoot } from "../entry/ssr-root.js";
6
6
  import { RouteLoader } from "../lib/routing/loader.js";
7
- export async function renderPageToSSRStream(pathname, initialData, serverContext) {
8
- const clientManifest = serverContext.runtime.getManifest("client");
7
+ import { ServerContext } from "./server-context.js";
8
+ import { Writable } from "stream";
9
+ export async function getSsrStream(args) {
10
+ const clientManifest = ServerContext.main.runtime.getManifest("client");
9
11
  const assets = await clientManifest.inputs[clientManifest.handler].assets();
10
- const jsx = (_jsx(SSRRoot, { assets: _jsx(Suspense, { children: assets.map((m) => renderAsset(m)) }), metaTags: initialData?.meta?.head || [], pathname: pathname, initialData: initialData, loader: new RouteLoader() }));
12
+ const jsx = (_jsx(SSRRoot, { assets: _jsx(Suspense, { children: assets.map((m) => renderAsset(m)) }), metaTags: args.initialData?.meta?.head || [], pathname: args.pathname, initialData: args.initialData, loader: new RouteLoader() }));
11
13
  const stream = await new Promise(async (resolve, reject) => {
12
14
  // console.log("Rendering to pipable")
13
15
  const stream = renderToPipeableStream(jsx, {
@@ -17,15 +19,82 @@ export async function renderPageToSSRStream(pathname, initialData, serverContext
17
19
  },
18
20
  onShellError(err) {
19
21
  console.log("onShellError", err);
20
- resolve("An error occurred");
22
+ reject(err);
21
23
  },
22
24
  onError(err, errInfo) {
23
25
  console.log("Error occurred after shell ready", err, errInfo);
24
26
  console.error(err);
25
27
  },
26
28
  bootstrapModules: [clientManifest.inputs[clientManifest.handler].output.path],
27
- bootstrapScriptContent: `window.manifest = ${JSON.stringify(await clientManifest.json())};\nwindow._PAGE_DATA = ${JSON.stringify(initialData)};\nwindow._TRACKERS = ${JSON.stringify(initialData.trackers)}`,
29
+ bootstrapScriptContent: `window.manifest = ${JSON.stringify(await clientManifest.json())};\nwindow._PAGE_DATA = ${JSON.stringify(args.initialData)};\nwindow._TRACKERS = ${JSON.stringify(args.initialData.trackers)}`,
28
30
  });
29
31
  });
30
- return stream;
32
+ return new ReadableStream({
33
+ async start(controller) {
34
+ const writableStream = new Writable({
35
+ emitClose: true,
36
+ write(chunk, encoding, callback) {
37
+ controller.enqueue(chunk);
38
+ callback();
39
+ },
40
+ final(callback) {
41
+ controller.close();
42
+ callback();
43
+ },
44
+ });
45
+ stream.pipe(writableStream);
46
+ },
47
+ });
48
+ }
49
+ export async function renderPage(args) {
50
+ const serverContext = ServerContext.main;
51
+ let headers = new Headers();
52
+ let responseInit = {
53
+ headers,
54
+ };
55
+ try {
56
+ const [{ appData, trackers }, response] = await Promise.all([
57
+ serverContext.fetchAppData(),
58
+ serverContext.fetchRouteData({
59
+ pathname: args.pathname,
60
+ withAppData: false,
61
+ headers: {},
62
+ query: {},
63
+ }),
64
+ ]);
65
+ let data;
66
+ try {
67
+ data = await response.json();
68
+ data.appData = appData;
69
+ data.trackers = trackers;
70
+ }
71
+ catch (err) {
72
+ data = {
73
+ view: "_error",
74
+ viewType: "react",
75
+ viewData: {},
76
+ appData: appData,
77
+ };
78
+ console.error(err);
79
+ responseInit.status = 500;
80
+ }
81
+ headers.set("Content-Type", "text/html; charset=utf-8");
82
+ const stream = await getSsrStream({
83
+ ...args,
84
+ initialData: data,
85
+ });
86
+ return new Response(stream, responseInit);
87
+ }
88
+ catch (err) {
89
+ console.error(err);
90
+ return new Response('<!DOCTYPE html><html><head><title>500 Internal Server Error</title></head><body><h1>500 Internal Server Error</h1><p>"' +
91
+ String(err) +
92
+ '"</p></body></html>', {
93
+ status: 500,
94
+ statusText: "Internal Server Error",
95
+ headers: {
96
+ "Content-Type": "text/html; charset=utf-8",
97
+ },
98
+ });
99
+ }
31
100
  }
@@ -0,0 +1,56 @@
1
+ import { AnyProcedure } from "@trpc/server";
2
+ import { FetchCreateContextFnOptions } from "@trpc/server/adapters/fetch";
3
+ export declare const rpcApi: {
4
+ _config: import("@trpc/server/unstable-core-do-not-import").RootConfig<{
5
+ ctx: RPCContext;
6
+ meta: object;
7
+ errorShape: import("@trpc/server/unstable-core-do-not-import").DefaultErrorShape;
8
+ transformer: true;
9
+ }>;
10
+ procedure: import("@trpc/server/unstable-core-do-not-import").ProcedureBuilder<RPCContext, object, object, typeof import("@trpc/server/unstable-core-do-not-import").unsetMarker, typeof import("@trpc/server/unstable-core-do-not-import").unsetMarker, typeof import("@trpc/server/unstable-core-do-not-import").unsetMarker, typeof import("@trpc/server/unstable-core-do-not-import").unsetMarker, false>;
11
+ middleware: <$ContextOverrides>(fn: import("@trpc/server/unstable-core-do-not-import").MiddlewareFunction<RPCContext, object, object, $ContextOverrides, unknown>) => import("@trpc/server/unstable-core-do-not-import").MiddlewareBuilder<RPCContext, object, $ContextOverrides, unknown>;
12
+ router: {
13
+ <TInput extends import("@trpc/server").RouterRecord>(input: TInput): import("@trpc/server/unstable-core-do-not-import").BuiltRouter<{
14
+ ctx: RPCContext;
15
+ meta: object;
16
+ errorShape: import("@trpc/server/unstable-core-do-not-import").DefaultErrorShape;
17
+ transformer: true;
18
+ }, TInput>;
19
+ <TInput extends import("@trpc/server/unstable-core-do-not-import").CreateRouterOptions>(input: TInput): import("@trpc/server/unstable-core-do-not-import").BuiltRouter<{
20
+ ctx: RPCContext;
21
+ meta: object;
22
+ errorShape: import("@trpc/server/unstable-core-do-not-import").DefaultErrorShape;
23
+ transformer: true;
24
+ }, import("@trpc/server/unstable-core-do-not-import").DecorateCreateRouterOptions<TInput>>;
25
+ };
26
+ mergeRouters: typeof import("@trpc/server/unstable-core-do-not-import").mergeRouters;
27
+ createCallerFactory: <TRecord extends import("@trpc/server").RouterRecord>(router: Pick<import("@trpc/server/unstable-core-do-not-import").Router<{
28
+ ctx: RPCContext;
29
+ meta: object;
30
+ errorShape: import("@trpc/server/unstable-core-do-not-import").DefaultErrorShape;
31
+ transformer: true;
32
+ }, TRecord>, "_def">) => import("@trpc/server/unstable-core-do-not-import").RouterCaller<{
33
+ ctx: RPCContext;
34
+ meta: object;
35
+ errorShape: import("@trpc/server/unstable-core-do-not-import").DefaultErrorShape;
36
+ transformer: true;
37
+ }, TRecord>;
38
+ };
39
+ type RouterSchema = Record<string, Record<string, AnyProcedure> | AnyProcedure>;
40
+ export declare const rpc: {
41
+ middleware: <$ContextOverrides>(fn: import("@trpc/server/unstable-core-do-not-import").MiddlewareFunction<RPCContext, object, object, $ContextOverrides, unknown>) => import("@trpc/server/unstable-core-do-not-import").MiddlewareBuilder<RPCContext, object, $ContextOverrides, unknown>;
42
+ procedure: import("@trpc/server/unstable-core-do-not-import").ProcedureBuilder<RPCContext, object, object, typeof import("@trpc/server/unstable-core-do-not-import").unsetMarker, typeof import("@trpc/server/unstable-core-do-not-import").unsetMarker, typeof import("@trpc/server/unstable-core-do-not-import").unsetMarker, typeof import("@trpc/server/unstable-core-do-not-import").unsetMarker, false>;
43
+ router<T extends RouterSchema>(routes: T): T;
44
+ };
45
+ export declare function defineServerContext<T>(func: (opts: FetchCreateContextFnOptions) => T): (opts: FetchCreateContextFnOptions) => T;
46
+ export declare function instantiateRouter<T extends RouterSchema>(routes: T): import("@trpc/server/unstable-core-do-not-import").BuiltRouter<{
47
+ ctx: RPCContext;
48
+ meta: object;
49
+ errorShape: import("@trpc/server/unstable-core-do-not-import").DefaultErrorShape;
50
+ transformer: true;
51
+ }, T>;
52
+ export type InferRPCServerContext<TFunc extends null | ((opts: FetchCreateContextFnOptions) => any)> = {
53
+ req: Request;
54
+ resHeaders: Headers;
55
+ } & (TFunc extends (opts: FetchCreateContextFnOptions) => infer T ? T : {});
56
+ export {};
@@ -0,0 +1,18 @@
1
+ import { initTRPC } from "@trpc/server";
2
+ import superjson from "superjson";
3
+ export const rpcApi = initTRPC.context().create({
4
+ transformer: superjson,
5
+ });
6
+ export const rpc = {
7
+ middleware: rpcApi.middleware,
8
+ procedure: rpcApi.procedure,
9
+ router(routes) {
10
+ return routes;
11
+ },
12
+ };
13
+ export function defineServerContext(func) {
14
+ return func;
15
+ }
16
+ export function instantiateRouter(routes) {
17
+ return rpcApi.router(routes);
18
+ }
@@ -21,6 +21,7 @@ export declare class ServerContext {
21
21
  dev: boolean;
22
22
  origin: string;
23
23
  replaceUrls?: (text: string) => string;
24
+ static main: ServerContext;
24
25
  constructor(conf: ServerContextArgs);
25
26
  get runtime(): ServerContextRuntime;
26
27
  static setRuntime(rt: ServerContextRuntime): void;
@@ -18,12 +18,14 @@ export class ServerContext {
18
18
  dev;
19
19
  origin;
20
20
  replaceUrls;
21
+ static main;
21
22
  constructor(conf) {
22
23
  this.dev = conf.dev;
23
24
  this.origin = conf.origin;
24
25
  if (conf.replaceUrls) {
25
26
  this.replaceUrls = createUrlReplacer(conf.replaceUrls);
26
27
  }
28
+ ServerContext.main = this;
27
29
  }
28
30
  get runtime() {
29
31
  return runtime;
@@ -0,0 +1,2 @@
1
+ import { PropsWithChildren } from "react";
2
+ export declare function APIProvider(props: PropsWithChildren<{}>): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,5 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { QueryProvider } from "./query-client.js";
3
+ export function APIProvider(props) {
4
+ return _jsx(QueryProvider, { children: props.children });
5
+ }
@@ -1,5 +1,5 @@
1
1
  import { Component, ErrorInfo, ReactNode } from "react";
2
- import { BlocksContext, ContentBlock } from "../lib/blocks/ContentBlocks";
2
+ import { BlocksContext, ContentBlock } from "../lib/blocks/ContentBlocks.js";
3
3
  interface Props {
4
4
  block: ContentBlock;
5
5
  blockContext: BlocksContext;
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { Component } from "react";
3
- import { errorHandling } from "../lib/runtime";
4
- import { ErrorMessage } from "./ErrorMessage";
3
+ import { errorHandling } from "../lib/runtime/errorHandling.js";
4
+ import { ErrorMessage } from "./ErrorMessage.js";
5
5
  export class BlockErrorBoundary extends Component {
6
6
  state = {
7
7
  hasError: false,
@@ -1,5 +1,5 @@
1
1
  import { Component, ErrorInfo, ReactNode } from "react";
2
- import { RouteState } from "../lib/routing";
2
+ import { RouteState } from "../lib/routing/types.js";
3
3
  interface Props {
4
4
  route: RouteState;
5
5
  children: ReactNode;
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { Component } from "react";
3
- import { errorHandling } from "../lib/runtime";
4
- import { ErrorMessage } from "./ErrorMessage";
3
+ import { errorHandling } from "../lib/runtime/errorHandling.js";
4
+ import { ErrorMessage } from "./ErrorMessage.js";
5
5
  export class RouteErrorBoundary extends Component {
6
6
  state = {
7
7
  hasError: false,
@@ -1,2 +1,4 @@
1
1
  import { QueryClient } from "@tanstack/react-query";
2
+ import { PropsWithChildren } from "react";
2
3
  export declare function getQueryClient(): QueryClient;
4
+ export declare function QueryProvider(props: PropsWithChildren<{}>): import("react/jsx-runtime").JSX.Element;
@@ -1,4 +1,5 @@
1
- import { QueryClient } from "@tanstack/react-query";
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { QueryClientProvider, QueryClient } from "@tanstack/react-query";
2
3
  let queryClient = null;
3
4
  export function getQueryClient() {
4
5
  if (!queryClient) {
@@ -14,3 +15,6 @@ export function getQueryClient() {
14
15
  }
15
16
  return queryClient;
16
17
  }
18
+ export function QueryProvider(props) {
19
+ return _jsx(QueryClientProvider, { client: getQueryClient(), children: props.children });
20
+ }
@@ -0,0 +1,2 @@
1
+ import { TRPCUntypedClient } from "@trpc/client";
2
+ export declare function getRPCClient(): TRPCUntypedClient<any>;
@@ -0,0 +1,34 @@
1
+ import { createTRPCUntypedClient, httpLink, splitLink, unstable_httpSubscriptionLink, } from "@trpc/client";
2
+ import SuperJSON from "superjson";
3
+ import { parseURL, stringifyParsedURL } from "ufo";
4
+ let client;
5
+ export function getRPCClient() {
6
+ if (env.rpcEnabled) {
7
+ if (!client) {
8
+ // @ts-ignore
9
+ const endpoint = env.serverless ? "/" : window.SERVERLESS_ENDPOINT ?? "/";
10
+ client = createTRPCUntypedClient({
11
+ links: [
12
+ splitLink({
13
+ // uses the httpSubscriptionLink for subscriptions
14
+ condition: (op) => op.type === "subscription",
15
+ true: unstable_httpSubscriptionLink({
16
+ url: endpoint,
17
+ transformer: SuperJSON,
18
+ }),
19
+ false: httpLink({
20
+ url: endpoint,
21
+ fetch: (input, init) => {
22
+ const parsed = parseURL(input);
23
+ parsed.pathname = "/" + parsed.pathname.replace(/(^\/|\/$)/g, "").replace(/\./g, "/") + "/";
24
+ return fetch(stringifyParsedURL(parsed), init);
25
+ },
26
+ transformer: SuperJSON,
27
+ }),
28
+ }),
29
+ ],
30
+ });
31
+ }
32
+ }
33
+ return client;
34
+ }
@@ -1 +1 @@
1
- export declare const VERSION = "2.0.0-beta.57";
1
+ export declare const VERSION = "2.0.0-beta.58";
@@ -1 +1 @@
1
- export const VERSION = "2.0.0-beta.57";
1
+ export const VERSION = "2.0.0-beta.58";
@@ -39,6 +39,7 @@ export class DevServer {
39
39
  publicUrl: this.project.publicUrl,
40
40
  rootDir: this.project.rootDir,
41
41
  log: console,
42
+ rpcBases: (await this.project.serverRoutes.get()).bases,
42
43
  });
43
44
  const preset = process.env.TARGET ??
44
45
  process.env.PRESET ??
@@ -15,7 +15,7 @@ export function envPlugin(args) {
15
15
  themePath: JSON.stringify(args.publicUrl),
16
16
  devUI: args.mode === "development" ? "true" : "false",
17
17
  serverlessOrigin: JSON.stringify("http://serverleress-endpoint"),
18
- rpcEnabled: "false",
18
+ rpcEnabled: "true",
19
19
  origin: JSON.stringify(process.env.SITE_URL ?? "/"),
20
20
  };
21
21
  const expandDefines = (obj, prefixes = []) => {
@@ -7,6 +7,7 @@ export type AppArgs = {
7
7
  log?: StatefulLog<any>;
8
8
  preset?: string;
9
9
  routes?: CustomRoute[];
10
+ rpcBases?: string[];
10
11
  };
11
12
  type HTTPMethod = "GET" | "POST" | "PUT" | "OPTIONS" | "HEAD";
12
13
  type CustomRouteFunction = (req: Request) => Response;
@@ -11,6 +11,7 @@ export function createVinxiApp(args) {
11
11
  mode: args.mode,
12
12
  serverless: true,
13
13
  });
14
+ console.log("Creating Vinxi app with args", args.rpcBases);
14
15
  return createApp({
15
16
  server: {
16
17
  // experimental: {
@@ -76,6 +77,24 @@ export function createVinxiApp(args) {
76
77
  dir: "./assets",
77
78
  base: joinURL(args.publicUrl, "assets"),
78
79
  },
80
+ {
81
+ name: "trpc-api",
82
+ type: "http",
83
+ base: "/trpc/",
84
+ handler: `${folder}/handler.trpc-api.ts`,
85
+ target: "server",
86
+ plugins: () => [
87
+ tsconfigPaths(),
88
+ envPlugin({
89
+ rootDir: args.rootDir,
90
+ console: log,
91
+ mode: args.mode,
92
+ publicUrl: args.publicUrl,
93
+ serverless: true,
94
+ target: "frontend",
95
+ }),
96
+ ],
97
+ },
79
98
  {
80
99
  name: "data-api",
81
100
  type: "http",
@@ -87,7 +106,7 @@ export function createVinxiApp(args) {
87
106
  envPlugin({
88
107
  rootDir: args.rootDir,
89
108
  console: log,
90
- mode: "development",
109
+ mode: args.mode,
91
110
  publicUrl: args.publicUrl,
92
111
  serverless: true,
93
112
  target: "frontend",
@@ -105,7 +124,7 @@ export function createVinxiApp(args) {
105
124
  envPlugin({
106
125
  rootDir: args.rootDir,
107
126
  console: log,
108
- mode: "development",
127
+ mode: args.mode,
109
128
  publicUrl: args.publicUrl,
110
129
  serverless: true,
111
130
  target: "frontend",
@@ -121,7 +140,7 @@ export function createVinxiApp(args) {
121
140
  ...corePlugins({
122
141
  rootDir: args.rootDir,
123
142
  console: log,
124
- mode: "development",
143
+ mode: args.mode,
125
144
  publicUrl: args.publicUrl,
126
145
  serverless: true,
127
146
  target: "frontend",
@@ -138,7 +157,7 @@ export function createVinxiApp(args) {
138
157
  ...corePlugins({
139
158
  rootDir: args.rootDir,
140
159
  console: log,
141
- mode: "development",
160
+ mode: args.mode,
142
161
  publicUrl: args.publicUrl,
143
162
  serverless: true,
144
163
  target: "cms",
@@ -146,6 +165,24 @@ export function createVinxiApp(args) {
146
165
  ],
147
166
  base: "/_admin",
148
167
  },
168
+ ...(args.rpcBases ?? []).map((base) => ({
169
+ name: "trpc-api",
170
+ type: "http",
171
+ base: "/" + base.replace(/^\//, ""),
172
+ handler: `${folder}/handler.trpc-api.ts`,
173
+ target: "server",
174
+ plugins: () => [
175
+ tsconfigPaths(),
176
+ envPlugin({
177
+ rootDir: args.rootDir,
178
+ console: log,
179
+ mode: args.mode,
180
+ publicUrl: args.publicUrl,
181
+ serverless: true,
182
+ target: "frontend",
183
+ }),
184
+ ],
185
+ })),
149
186
  {
150
187
  name: "ssr",
151
188
  type: "http",
@@ -155,7 +192,7 @@ export function createVinxiApp(args) {
155
192
  ...corePlugins({
156
193
  rootDir: args.rootDir,
157
194
  console: log,
158
- mode: "development",
195
+ mode: args.mode,
159
196
  publicUrl: args.publicUrl,
160
197
  serverless: true,
161
198
  target: "frontend",
@@ -1,5 +1,6 @@
1
1
  import { code, imp } from "ts-poet";
2
2
  import { FSCodegen } from "../utils/fs-codegen.js";
3
+ import { camelCase } from "change-case-all";
3
4
  export function getVinxiFolder(opts) {
4
5
  return (opts.mode === "development" ? "dev" : "prod") + (opts.serverless ? "" : "-spa");
5
6
  }
@@ -246,55 +247,58 @@ export function createVinxiCodegen(opts) {
246
247
  import "./manifest/blocks.js"
247
248
  import "./manifest/styles.js"
248
249
  import "./manifest/views.js"
250
+ import "./context.js"
249
251
 
250
- import { proxyWpAdmin, renderPageToSSRStream } from "eddev/server"
251
- import { eventHandler, getRequestURL, setResponseHeader, setResponseStatus } from "vinxi/http"
252
- import { serverContext } from "./context.js"
252
+ import { proxyWpAdmin, ServerContext, renderPage } from "eddev/server"
253
+ import { eventHandler, getRequestURL } from "vinxi/http"
253
254
  import { RouteData } from "eddev/routing"
254
255
 
255
256
  export default eventHandler({
256
257
  handler: async (event) => {
258
+ const serverContext = ServerContext.main
257
259
  const url = getRequestURL(event)
258
260
 
259
261
  if (url.pathname.includes(".")) {
260
- return proxyWpAdmin(event, serverContext)
262
+ return proxyWpAdmin(event)
261
263
  }
262
264
 
263
- try {
264
- const [{appData, trackers}, response] = await Promise.all([
265
- serverContext.fetchAppData(),
266
- serverContext.fetchRouteData({
267
- pathname: url.pathname,
268
- withAppData: false,
269
- headers: {},
270
- query: {},
271
- }),
272
- ])
273
-
274
- let data: RouteData
275
- try {
276
- data = await response.json()
277
- data.appData = appData
278
- data.trackers = trackers
279
- } catch (err) {
280
- data = {
281
- view: "_error",
282
- viewType: "react",
283
- viewData: {},
284
- appData: appData,
285
- }
286
- console.error(err)
287
- setResponseStatus(event, 500)
288
- }
289
- setResponseHeader(event, "Content-Type", "text/html; charset=utf-8")
290
- return renderPageToSSRStream(url.pathname, data, serverContext)
291
- } catch (err) {
292
- console.error(err)
293
- setResponseStatus(event, 500)
294
- setResponseHeader(event, "Content-Type", "text/html; charset=utf-8")
295
- return '<!DOCTYPE html><html><head><title>500 Internal Server Error</title></head><body><h1>500 Internal Server Error</h1><p>"'+err.message+'"</p></body></html>'
296
- }
297
- },
265
+ return renderPage({ pathname: url.pathname })
266
+
267
+ // try {
268
+ // const [{appData, trackers}, response] = await Promise.all([
269
+ // serverContext.fetchAppData(),
270
+ // serverContext.fetchRouteData({
271
+ // pathname: url.pathname,
272
+ // withAppData: false,
273
+ // headers: {},
274
+ // query: {},
275
+ // }),
276
+ // ])
277
+
278
+ // let data: RouteData
279
+ // try {
280
+ // data = await response.json()
281
+ // data.appData = appData
282
+ // data.trackers = trackers
283
+ // } catch (err) {
284
+ // data = {
285
+ // view: "_error",
286
+ // viewType: "react",
287
+ // viewData: {},
288
+ // appData: appData,
289
+ // }
290
+ // console.error(err)
291
+ // setResponseStatus(event, 500)
292
+ // }
293
+ // setResponseHeader(event, "Content-Type", "text/html; charset=utf-8")
294
+ // return renderPageToSSRStream(url.pathname, data)
295
+ // } catch (err) {
296
+ // console.error(err)
297
+ // setResponseStatus(event, 500)
298
+ // setResponseHeader(event, "Content-Type", "text/html; charset=utf-8")
299
+ // return '<!DOCTYPE html><html><head><title>500 Internal Server Error</title></head><body><h1>500 Internal Server Error</h1><p>"'+err.message+'"</p></body></html>'
300
+ // }
301
+ }
298
302
  })
299
303
  `,
300
304
  });
@@ -306,10 +310,10 @@ export function createVinxiCodegen(opts) {
306
310
  /// <reference types="vinxi/types/server" />
307
311
  import { proxyWpAdmin } from "eddev/server"
308
312
  import { eventHandler } from "vinxi/http"
309
- import { serverContext } from "./context.js"
313
+ import "./context.js"
310
314
 
311
315
  export default eventHandler(async (event) => {
312
- return proxyWpAdmin(event, serverContext)
316
+ return proxyWpAdmin(event)
313
317
  })
314
318
  `,
315
319
  });
@@ -460,5 +464,84 @@ export function createVinxiCodegen(opts) {
460
464
  `;
461
465
  },
462
466
  });
467
+ if (opts.serverless) {
468
+ codegen.registerFile({
469
+ name: "manifest/routes.ts",
470
+ generate: async () => {
471
+ const routeManifest = await project.serverRoutes.get();
472
+ return code /* ts */ `
473
+ import { instantiateRouter } from "eddev/server"
474
+ ${routeManifest.contextFileName
475
+ ? code /*ts*/ `
476
+ import createContext from "../../../${routeManifest.contextFileName}"
477
+ `
478
+ : code /*ts*/ `
479
+ const createContext = () => ({})
480
+ `}
481
+
482
+ const router = instantiateRouter({${Object.entries(routeManifest.routes).map(([name, route]) => {
483
+ const src = "../../../" + route.fileName;
484
+ const importStatement = imp(camelCase(name) + "=" + src);
485
+ return code `${JSON.stringify(route.prefix)}: ${importStatement},\n`;
486
+ })}})
487
+
488
+ export { createContext, router }
489
+ `;
490
+ },
491
+ subscribe: project.serverRoutes.subscribe,
492
+ });
493
+ codegen.registerFile({
494
+ name: "handler.trpc-api.ts",
495
+ generate: code /* tsx */ `
496
+ /// <reference types="vinxi/types/server" />
497
+ import "./context.js"
498
+ import { fetchRequestHandler } from "@trpc/server/adapters/fetch"
499
+ import { eventHandler, getWebRequest } from "vinxi/http"
500
+ import { createContext, router } from "./manifest/routes.ts"
501
+ import { parseURL, stringifyParsedURL } from "ufo"
502
+
503
+ export default eventHandler({
504
+ handler: async (event) => {
505
+ // Update URLs with dots, which tRPC prefers
506
+ const originalReq = getWebRequest(event)
507
+ const parsed = parseURL(originalReq.url)
508
+ parsed.pathname = "/" + parsed.pathname.replace(/(^\\/|\\/$)/g, "").replace(/\\//, ".")
509
+ const req = new Request(stringifyParsedURL(parsed), originalReq)
510
+
511
+ // Handle any early results which are Responses
512
+ function processEarlyResult(value: any): Response | undefined {
513
+ if (value instanceof Response) {
514
+ return value
515
+ }
516
+ }
517
+
518
+ return new Promise(async (resolve) => {
519
+ let sent = false
520
+ const defaultResponse = await fetchRequestHandler({
521
+ endpoint: "/",
522
+ req: req,
523
+ router: router,
524
+ createContext,
525
+ onError: (err) => console.error(err),
526
+ batching: { enabled: false },
527
+ // If a Response object is returned by a route, it will be sent as the response
528
+ responseMeta(opts) {
529
+ const value = opts?.data?.[0]?.["result"]?.["data"]
530
+ const response = processEarlyResult(value)
531
+ if (response) {
532
+ sent = true
533
+ resolve(response)
534
+ }
535
+ return {}
536
+ },
537
+ })
538
+ if (sent) return
539
+ resolve(defaultResponse)
540
+ })
541
+ },
542
+ })
543
+ `,
544
+ });
545
+ }
463
546
  return codegen;
464
547
  }
@@ -31,6 +31,7 @@ export declare class GraphQLGenerator {
31
31
  private validateGraphQLFiles;
32
32
  private generateTS;
33
33
  generateUtilTypes(): Promise<unknown[]>;
34
+ generateAPITypes(): Promise<unknown[]>;
34
35
  /**
35
36
  * Saves the schema to a file, for use by the VSCode GraphQL extension
36
37
  */
@@ -9,7 +9,7 @@ import { createGraphQLFileLoader } from "./query-files-loader.js";
9
9
  import * as typescriptPlugin from "@graphql-codegen/typescript";
10
10
  import * as typescriptOperationsPlugin from "@graphql-codegen/typescript-operations";
11
11
  import chalk from "chalk";
12
- import { code } from "ts-poet";
12
+ import { code, imp } from "ts-poet";
13
13
  import { highlightCode } from "../utils/highlight-code.js";
14
14
  import { createConsole } from "../utils/stateful-log.js";
15
15
  import { watchFileTreeForChanges } from "../utils/watch-file-tree.js";
@@ -17,6 +17,7 @@ import pluginFiles from "./plugins/gql-plugin-files.js";
17
17
  import pluginNoDuplicates from "./plugins/gql-plugin-no-duplicates.js";
18
18
  import pluginQueries from "./plugins/gql-plugin-queries.js";
19
19
  import { FSCodegen } from "../utils/fs-codegen.js";
20
+ import { camelCase } from "change-case-all";
20
21
  export const graphqlLog = createConsole("GraphQL Codegen", "graphql");
21
22
  const console = graphqlLog;
22
23
  class GraphQLValidationError {
@@ -153,6 +154,9 @@ export class GraphQLGenerator {
153
154
  this.project.blocks.subscribeFuture(() => {
154
155
  this.generateUtilTypes();
155
156
  });
157
+ this.project.serverRoutes.subscribeFuture(() => {
158
+ this.generateAPITypes();
159
+ });
156
160
  this.listen();
157
161
  }
158
162
  if (this.opts.optimize) {
@@ -280,6 +284,7 @@ export class GraphQLGenerator {
280
284
  };
281
285
  const errors = (await Promise.all([
282
286
  this.generateUtilTypes(),
287
+ this.generateAPITypes(),
283
288
  this.generateTS("types.graphql.ts", schemaResult.rawSchema, {
284
289
  documents: getDocuments(["queries", "views", "blocks", "fragments"]),
285
290
  hasDocuments: true,
@@ -624,6 +629,42 @@ export class GraphQLGenerator {
624
629
  }
625
630
  return [];
626
631
  }
632
+ async generateAPITypes() {
633
+ const filename = join(this.project.rootDir, "types.api.ts");
634
+ try {
635
+ const routeManifest = await this.project.serverRoutes.get();
636
+ const contents = code /*ts*/ `
637
+ import "eddev/types.app.public";
638
+ import { InferRPCServerContext, rpc } from "eddev/server"
639
+ import { finalizeRPCRouter } from "eddev/_internal"
640
+ ${routeManifest.contextFileName
641
+ ? code /*ts*/ `
642
+ import createContext from "./${routeManifest.contextFileName.replace(/\.tsx?$/, "")}"
643
+ `
644
+ : code /*ts*/ `
645
+ const createContext = () => ({})
646
+ `}
647
+
648
+ function createRouter() {
649
+ return finalizeRPCRouter({${Object.entries(routeManifest.routes).map(([name, route]) => {
650
+ const src = "./" + route.fileName;
651
+ const importStatement = imp(camelCase(name) + "=" + src.replace(/\.tsx?$/, ""));
652
+ return code `${JSON.stringify(route.prefix)}: ${importStatement},\n`;
653
+ })}})
654
+ }
655
+
656
+ declare global {
657
+ interface RPCContext extends InferRPCServerContext<typeof createContext> {}
658
+ interface RPCRouter extends ReturnType<typeof createRouter> {}
659
+ }
660
+ `;
661
+ await fs.writeIfUnchanged(filename, contents.toString());
662
+ }
663
+ catch (err) {
664
+ return [err];
665
+ }
666
+ return [];
667
+ }
627
668
  /**
628
669
  * Saves the schema to a file, for use by the VSCode GraphQL extension
629
670
  */
@@ -0,0 +1,20 @@
1
+ import { Project } from "../project.js";
2
+ export type RouteManifest = {
3
+ routes: Record<string, RouteInfo>;
4
+ contextFileName: string | null;
5
+ validationMessages: {
6
+ fieldKey: string;
7
+ message: string;
8
+ severity: "error" | "warning";
9
+ }[];
10
+ bases: string[];
11
+ };
12
+ type RouteInfo = {
13
+ kind: "context" | "route";
14
+ fileName: string;
15
+ prefix?: string;
16
+ error?: string;
17
+ };
18
+ export type RouteManifestGenerator = ReturnType<typeof loadRouteManifest>;
19
+ export declare function loadRouteManifest(project: Project): import("./manifest.js").ManifestGenerator<RouteInfo, RouteManifest>;
20
+ export {};
@@ -0,0 +1,74 @@
1
+ import { cliMode } from "../../cli/cli-mode.js";
2
+ import { createManifestGenerator } from "./manifest.js";
3
+ export function loadRouteManifest(project) {
4
+ return createManifestGenerator({
5
+ baseDir: project.rootDir,
6
+ pattern: ["server/routes/**/*.{ts,tsx}", "server/_context.{ts,tsx}"],
7
+ watch: cliMode.watch,
8
+ async generateManifest(entries) {
9
+ let result = {
10
+ routes: {},
11
+ contextFileName: null,
12
+ validationMessages: [],
13
+ bases: [],
14
+ };
15
+ const bases = new Set();
16
+ Object.entries(entries)
17
+ .sort(([b1], [b2]) => {
18
+ return b1.localeCompare(b2);
19
+ })
20
+ .forEach(([key, entry]) => {
21
+ if (entry.value.kind === "context") {
22
+ result.contextFileName = entry.value.fileName;
23
+ }
24
+ else if (entry.value.kind === "route") {
25
+ const { error: initialError } = entry.value;
26
+ const prefix = entry.value.prefix;
27
+ result.routes[key] = entry.value;
28
+ if (prefix) {
29
+ let shouldAdd = true;
30
+ bases.forEach((base) => {
31
+ if (base.startsWith(prefix)) {
32
+ bases.delete(base);
33
+ }
34
+ else if (prefix.startsWith(base)) {
35
+ shouldAdd = false;
36
+ return;
37
+ }
38
+ });
39
+ if (shouldAdd) {
40
+ bases.add(entry.value.prefix);
41
+ }
42
+ }
43
+ if (initialError) {
44
+ result.validationMessages.push({
45
+ fieldKey: key,
46
+ message: initialError,
47
+ severity: "error",
48
+ });
49
+ return;
50
+ }
51
+ }
52
+ });
53
+ result.bases = [...bases].sort().map((base) => "/" + base.replace(/\./g, "/"));
54
+ return result;
55
+ },
56
+ getKey(path) {
57
+ // Strip the views folder name + extension
58
+ return path.replace(/\.tsx?$/, "").replace(/^server\/routes\//, "");
59
+ },
60
+ async loadValue(fileName, key) {
61
+ if (fileName.startsWith("server/_context.")) {
62
+ return {
63
+ kind: "context",
64
+ fileName,
65
+ };
66
+ }
67
+ return {
68
+ kind: "route",
69
+ prefix: key.replace("/index", "").replace(/\//, "."),
70
+ fileName,
71
+ };
72
+ },
73
+ });
74
+ }
@@ -1,6 +1,7 @@
1
1
  import { EDConfig } from "./config.js";
2
2
  import { BlockManifestGenerator } from "./manifest/block-manifest.js";
3
3
  import { FieldManifestGenerator } from "./manifest/field-manifest.js";
4
+ import { RouteManifestGenerator } from "./manifest/routes-manifest.js";
4
5
  import { ViewManifestGenerator } from "./manifest/view-manifest.js";
5
6
  import { WidgetManifestGenerator } from "./manifest/widget-manifest.js";
6
7
  export declare const projectLog: import("../utils/stateful-log.js").StatefulLog<Project>;
@@ -24,6 +25,7 @@ export declare class Project {
24
25
  views: ViewManifestGenerator;
25
26
  fields: FieldManifestGenerator;
26
27
  widgets: WidgetManifestGenerator;
28
+ serverRoutes: RouteManifestGenerator;
27
29
  private wp;
28
30
  reportPluginCompatibility: boolean;
29
31
  private constructor();
@@ -8,6 +8,7 @@ import { Configurator } from "./config.js";
8
8
  import { ProjectEnvUtils } from "./env.js";
9
9
  import { loadBlockManifest } from "./manifest/block-manifest.js";
10
10
  import { loadFieldManifest } from "./manifest/field-manifest.js";
11
+ import { loadRouteManifest } from "./manifest/routes-manifest.js";
11
12
  import { loadViewManifest } from "./manifest/view-manifest.js";
12
13
  import { loadWidgetManifest } from "./manifest/widget-manifest.js";
13
14
  import { WPInfo } from "./wp-info.js";
@@ -29,6 +30,7 @@ export class Project {
29
30
  views;
30
31
  fields;
31
32
  widgets;
33
+ serverRoutes;
32
34
  wp;
33
35
  reportPluginCompatibility = false;
34
36
  constructor(opts) {
@@ -39,6 +41,7 @@ export class Project {
39
41
  this.views = loadViewManifest(this);
40
42
  this.fields = loadFieldManifest(this);
41
43
  this.widgets = loadWidgetManifest(this);
44
+ this.serverRoutes = loadRouteManifest(this);
42
45
  this.wp = new WPInfo(this.origin);
43
46
  }
44
47
  async load() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eddev",
3
- "version": "2.0.0-beta.57",
3
+ "version": "2.0.0-beta.59",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -86,6 +86,9 @@
86
86
  "@nozbe/microfuzz": "^1.0.0",
87
87
  "@rollup/plugin-replace": "^5.0.5",
88
88
  "@tanstack/react-query": "^5.51.23",
89
+ "@trpc/client": "^11.0.0-rc.608",
90
+ "@trpc/react-query": "^11.0.0-rc.608",
91
+ "@trpc/server": "^11.0.0-rc.608",
89
92
  "@types/qs": "^6.9.15",
90
93
  "@vinxi/react": "^0.2.5",
91
94
  "@vitejs/plugin-react": "^4.1.1",
@@ -107,6 +110,7 @@
107
110
  "object-code": "^1.3.3",
108
111
  "qs": "^6.13.0",
109
112
  "react-super-seo": "^1.1.9",
113
+ "superjson": "^2.2.1",
110
114
  "ts-poet": "^6.6.0",
111
115
  "ufo": "^1.3.1",
112
116
  "undent": "^0.1.0",
package/types.app.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  /// <reference types="vite/client" />
2
2
  /// <reference types="./types.meta.d.ts" />
3
3
  /// <reference types="./types.env.d.ts" />
4
+ import { Router } from "@trpc/server"
4
5
 
5
6
  declare global {
6
7
  interface ViewProps {}
@@ -13,6 +14,7 @@ declare global {
13
14
  interface PostMetaTypes {}
14
15
 
15
16
  interface RPCRouter {}
17
+ interface RPCContext {}
16
18
 
17
19
  type AppData = ViewProps["_app"]
18
20