eddev 2.3.31 → 2.4.0-beta.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 (106) hide show
  1. package/dist/app/entry/ssr-root-client.d.ts +0 -2
  2. package/dist/app/entry/ssr-root-client.d.ts.map +1 -1
  3. package/dist/app/lib/blocks/block-debugger.d.ts.map +1 -1
  4. package/dist/app/lib/blocks/block-debugger.js +19 -2
  5. package/dist/app/lib/devtools/components/panels/StructurePanel.js +1 -1
  6. package/dist/app/server/assets.d.ts +45 -0
  7. package/dist/app/server/assets.d.ts.map +1 -0
  8. package/dist/app/server/assets.js +15 -0
  9. package/dist/app/server/index.d.ts +4 -0
  10. package/dist/app/server/index.d.ts.map +1 -1
  11. package/dist/app/server/index.js +3 -0
  12. package/dist/app/server/proxy-wp-admin.d.ts +6 -2
  13. package/dist/app/server/proxy-wp-admin.d.ts.map +1 -1
  14. package/dist/app/server/proxy-wp-admin.js +29 -57
  15. package/dist/app/server/render-ssr-page.d.ts +2 -6
  16. package/dist/app/server/render-ssr-page.d.ts.map +1 -1
  17. package/dist/app/server/render-ssr-page.js +9 -8
  18. package/dist/app/server/rpc-handler.d.ts +14 -0
  19. package/dist/app/server/rpc-handler.d.ts.map +1 -0
  20. package/dist/app/server/rpc-handler.js +63 -0
  21. package/dist/app/server/server-app.d.ts +22 -0
  22. package/dist/app/server/server-app.d.ts.map +1 -0
  23. package/dist/app/server/server-app.js +186 -0
  24. package/dist/app/server/server-context.d.ts +5 -5
  25. package/dist/app/server/server-context.d.ts.map +1 -1
  26. package/dist/app/server/server-context.js +21 -13
  27. package/dist/app/server/utils/fetch-origin.d.ts +13 -0
  28. package/dist/app/server/utils/fetch-origin.d.ts.map +1 -0
  29. package/dist/app/server/utils/fetch-origin.js +21 -0
  30. package/dist/app/server/utils/request.d.ts +20 -0
  31. package/dist/app/server/utils/request.d.ts.map +1 -0
  32. package/dist/app/server/utils/request.js +60 -0
  33. package/dist/node/cli/cli-worker.d.ts +10 -6
  34. package/dist/node/cli/cli-worker.d.ts.map +1 -1
  35. package/dist/node/cli/cli-worker.js +7 -14
  36. package/dist/node/cli/cli.js +37 -43
  37. package/dist/node/cli/display/CLIApp.d.ts +2 -4
  38. package/dist/node/cli/display/CLIApp.d.ts.map +1 -1
  39. package/dist/node/cli/display/CLIApp.js +2 -3
  40. package/dist/node/cli/version.d.ts +1 -1
  41. package/dist/node/cli/version.d.ts.map +1 -1
  42. package/dist/node/cli/version.js +1 -1
  43. package/dist/node/compiler/app-codegen.d.ts +18 -0
  44. package/dist/node/compiler/app-codegen.d.ts.map +1 -0
  45. package/dist/node/compiler/app-codegen.js +473 -0
  46. package/dist/node/compiler/build-serverless.d.ts +16 -0
  47. package/dist/node/compiler/build-serverless.d.ts.map +1 -0
  48. package/dist/node/compiler/build-serverless.js +40 -0
  49. package/dist/node/compiler/bundler.spa.d.ts +33 -0
  50. package/dist/node/compiler/bundler.spa.d.ts.map +1 -0
  51. package/dist/node/compiler/bundler.spa.js +59 -0
  52. package/dist/node/compiler/dev-css-links.d.ts +25 -0
  53. package/dist/node/compiler/dev-css-links.d.ts.map +1 -0
  54. package/dist/node/compiler/dev-css-links.js +87 -0
  55. package/dist/node/compiler/dev-server.d.ts +2 -0
  56. package/dist/node/compiler/dev-server.d.ts.map +1 -1
  57. package/dist/node/compiler/dev-server.js +43 -75
  58. package/dist/node/compiler/get-vite-config.d.ts +37 -6
  59. package/dist/node/compiler/get-vite-config.d.ts.map +1 -1
  60. package/dist/node/compiler/get-vite-config.js +113 -121
  61. package/dist/node/compiler/serverless-app.d.ts +35 -0
  62. package/dist/node/compiler/serverless-app.d.ts.map +1 -0
  63. package/dist/node/compiler/serverless-app.js +332 -0
  64. package/dist/node/compiler/transforms/block-meta.d.ts +10 -0
  65. package/dist/node/compiler/transforms/block-meta.d.ts.map +1 -0
  66. package/dist/node/compiler/transforms/block-meta.js +27 -0
  67. package/dist/node/compiler/transforms/component-names.d.ts +19 -0
  68. package/dist/node/compiler/transforms/component-names.d.ts.map +1 -0
  69. package/dist/node/compiler/transforms/component-names.js +45 -0
  70. package/dist/node/compiler/transforms/index.d.ts +36 -0
  71. package/dist/node/compiler/transforms/index.d.ts.map +1 -0
  72. package/dist/node/compiler/transforms/index.js +80 -0
  73. package/dist/node/compiler/transforms/types.d.ts +48 -0
  74. package/dist/node/compiler/transforms/types.d.ts.map +1 -0
  75. package/dist/node/compiler/transforms/types.js +1 -0
  76. package/dist/node/project/config.d.ts +1 -1
  77. package/dist/node/project/config.d.ts.map +1 -1
  78. package/dist/node/project/config.js +1 -1
  79. package/dist/node/project/env.js +1 -1
  80. package/dist/node/project/project-log.d.ts +7 -0
  81. package/dist/node/project/project-log.d.ts.map +1 -0
  82. package/dist/node/project/project-log.js +6 -0
  83. package/dist/node/project/project.d.ts +2 -2
  84. package/dist/node/project/project.d.ts.map +1 -1
  85. package/dist/node/project/project.js +3 -3
  86. package/dist/node/utils/fs.d.ts +70 -69
  87. package/dist/node/utils/fs.d.ts.map +1 -1
  88. package/package.json +12 -13
  89. package/skills/eddev/docs/devtool/cli.mdx +10 -8
  90. package/tsconfig.node.json +17 -5
  91. package/types.env.d.ts +1 -1
  92. package/dist/node/compiler/build-vinxi.d.ts +0 -9
  93. package/dist/node/compiler/build-vinxi.d.ts.map +0 -1
  94. package/dist/node/compiler/build-vinxi.js +0 -39
  95. package/dist/node/compiler/bundler.admin.d.ts +0 -14
  96. package/dist/node/compiler/bundler.admin.d.ts.map +0 -1
  97. package/dist/node/compiler/bundler.admin.js +0 -37
  98. package/dist/node/compiler/bundler.frontend.d.ts +0 -15
  99. package/dist/node/compiler/bundler.frontend.d.ts.map +0 -1
  100. package/dist/node/compiler/bundler.frontend.js +0 -51
  101. package/dist/node/compiler/vinxi-app.d.ts +0 -23
  102. package/dist/node/compiler/vinxi-app.d.ts.map +0 -1
  103. package/dist/node/compiler/vinxi-app.js +0 -261
  104. package/dist/node/compiler/vinxi-codegen.d.ts +0 -13
  105. package/dist/node/compiler/vinxi-codegen.d.ts.map +0 -1
  106. package/dist/node/compiler/vinxi-codegen.js +0 -764
@@ -0,0 +1,186 @@
1
+ import { invalidateByTag } from "@vercel/functions";
2
+ import { withTrailingSlash } from "ufo";
3
+ import { blockManifestReader } from "../lib/internal/read-block-manifest.js";
4
+ import { viewManifestReader } from "../lib/internal/read-view-manifest.js";
5
+ import { proxyWpAdmin } from "./proxy-wp-admin.js";
6
+ import { renderPageForIndexing } from "./render-ai-page.js";
7
+ import { renderPage } from "./render-ssr-page.js";
8
+ import { handleRPCRequest } from "./rpc-handler.js";
9
+ import { ServerContext } from "./server-context.js";
10
+ import { appendSetCookie, getCookie, getRawPath, getRequestHeaders, getRequestURL, withHeaders } from "./utils/request.js";
11
+ const BYPASS_COOKIE = "__prerender_bypass";
12
+ const json = (value, init) => Response.json(value, init);
13
+ const methodNotAllowed = () => new Response("Method Not Allowed", { status: 405 });
14
+ const isGet = (req) => req.method === "GET" || req.method === "HEAD";
15
+ /**
16
+ * The serverless app: route data, named queries and mutations, RPC procedures, WordPress proxying
17
+ * and server-rendered pages. Nitro calls `fetch` for every request that isn't a static asset or
18
+ * handled by a route rule (eg. the `/wp-content/**` proxies).
19
+ */
20
+ export function createServerApp(opts) {
21
+ ServerContext.setRuntime({ assets: opts.assets });
22
+ async function handleData(req, url) {
23
+ const serverContext = ServerContext.main;
24
+ const path = url.pathname;
25
+ if (path === "/_data/route" || path.startsWith("/_data/route/")) {
26
+ if (!isGet(req))
27
+ return methodNotAllowed();
28
+ const pathname = path.slice("/_data/route".length) || "/";
29
+ return serverContext.fetchRouteData({
30
+ pathname,
31
+ newOrigin: url.origin,
32
+ bypass: serverContext.shouldBypass(req),
33
+ });
34
+ }
35
+ if (path.startsWith("/_data/query/")) {
36
+ if (!isGet(req))
37
+ return methodNotAllowed();
38
+ // The query name and JSON params are encoded in the raw path: /_data/query/<name>=<params>
39
+ const queryPath = getRawPath(req).replace("/_data/query", "");
40
+ const paramSeparator = queryPath.indexOf("=");
41
+ const id = paramSeparator === -1 ? queryPath : queryPath.slice(0, paramSeparator);
42
+ const paramString = paramSeparator === -1 ? undefined : queryPath.slice(paramSeparator + 1);
43
+ let params = {};
44
+ try {
45
+ params =
46
+ typeof paramString === "string" && paramString.length
47
+ ? JSON.parse(decodeURIComponent(paramString.replace(/\/$/, "")))
48
+ : {};
49
+ }
50
+ catch (e) {
51
+ throw new Error("Invalid query parameters");
52
+ }
53
+ return serverContext.fetchNamedQuery({
54
+ name: id,
55
+ params,
56
+ headers: getRequestHeaders(req),
57
+ bypass: serverContext.shouldBypass(req),
58
+ });
59
+ }
60
+ if (path.startsWith("/_data/manifest/")) {
61
+ if (!isGet(req))
62
+ return methodNotAllowed();
63
+ const id = decodeURIComponent(path.slice("/_data/manifest/".length).replace(/\/$/, ""));
64
+ const assets = id === "handler" ? opts.assets.client : opts.assets.modules[id];
65
+ return json({ id, assets: assets ?? null });
66
+ }
67
+ if (path.startsWith("/_data/mutation/")) {
68
+ if (req.method !== "POST")
69
+ return methodNotAllowed();
70
+ const name = "/" + path.slice("/_data/mutation/".length);
71
+ const body = await req.json();
72
+ return serverContext.fetchMutation({ name, body, headers: getRequestHeaders(req) });
73
+ }
74
+ if (path === "/_data/submit-gf" || path === "/_data/submit-gf/") {
75
+ if (req.method !== "POST")
76
+ return methodNotAllowed();
77
+ const headers = new Headers(req.headers);
78
+ headers.delete("content-length");
79
+ headers.delete("host");
80
+ headers.delete("connection");
81
+ headers.delete("pragma");
82
+ return serverContext.fetchOrigin("/wp-json/ed/v1/gf/submit/", {
83
+ method: "POST",
84
+ headers,
85
+ body: await req.blob(),
86
+ });
87
+ }
88
+ return new Response("Not Found", { status: 404 });
89
+ }
90
+ async function handleAI(req, url) {
91
+ if (url.pathname !== "/_ai/page" && !url.pathname.startsWith("/_ai/page/")) {
92
+ return new Response("Not Found", { status: 404 });
93
+ }
94
+ if (!isGet(req))
95
+ return methodNotAllowed();
96
+ const pathname = url.pathname.slice("/_ai/page".length) || "/";
97
+ const page = await renderPageForIndexing({ pathname, newOrigin: url.origin });
98
+ return new Response(page.contents, {
99
+ headers: {
100
+ "Content-Type": "text/html; charset=utf-8",
101
+ "Cache-Control": "no-store",
102
+ },
103
+ });
104
+ }
105
+ /** Vercel prerender bypass helpers, used by the WordPress admin toolbar and cache purging. */
106
+ async function handleBypass(req, url) {
107
+ if (!isGet(req))
108
+ return methodNotAllowed();
109
+ const token = process.env.VERCEL_BYPASS_TOKEN;
110
+ const action = url.pathname.replace(/^\/_bypass\/?/, "").replace(/\/$/, "");
111
+ if (action === "enable") {
112
+ if (!token)
113
+ return json(false);
114
+ const headers = new Headers();
115
+ appendSetCookie(headers, BYPASS_COOKIE, token, { expires: new Date(Date.now() + 1000 * 60 * 60 * 24) });
116
+ return json(true, { headers });
117
+ }
118
+ if (action === "disable") {
119
+ const headers = new Headers();
120
+ appendSetCookie(headers, BYPASS_COOKIE, "");
121
+ return json(true, { headers });
122
+ }
123
+ if (action === "check") {
124
+ return json(!!token && getCookie(req, BYPASS_COOKIE) === token);
125
+ }
126
+ if (action === "purge") {
127
+ if (token && req.headers.get("x-prerender-revalidate") === token) {
128
+ await invalidateByTag("data");
129
+ return json(true);
130
+ }
131
+ return json(false);
132
+ }
133
+ return new Response("Not Found", { status: 404 });
134
+ }
135
+ return {
136
+ async fetch(req) {
137
+ const serverContext = ServerContext.main;
138
+ const url = getRequestURL(req);
139
+ await Promise.allSettled([viewManifestReader.preloadAll(), blockManifestReader.preloadAll()]);
140
+ // RPC
141
+ if (serverContext.rpcBases.some((base) => url.pathname.startsWith(base))) {
142
+ return handleRPCRequest(req, opts.rpc);
143
+ }
144
+ // Data API
145
+ if (url.pathname.startsWith("/_data/")) {
146
+ return handleData(req, url);
147
+ }
148
+ // LLM indexing route
149
+ if (url.pathname.startsWith("/_ai/")) {
150
+ return handleAI(req, url);
151
+ }
152
+ // Prerender bypass
153
+ if (url.pathname.startsWith("/_bypass/")) {
154
+ return handleBypass(req, url);
155
+ }
156
+ // Outdated build assets
157
+ if (url.pathname.match(/^\/(_build|_admin)\//)) {
158
+ return new Response("", { status: 404 });
159
+ }
160
+ // Proxy WordPress
161
+ if ((url.pathname.includes(".") && !url.pathname.includes("[")) ||
162
+ url.pathname.startsWith("/graphql") ||
163
+ url.pathname.startsWith("/wp-")) {
164
+ return proxyWpAdmin(req);
165
+ }
166
+ // Enforce trailing slashes
167
+ if (!url.pathname.endsWith("/")) {
168
+ url.pathname = withTrailingSlash(url.pathname);
169
+ return Response.redirect(url, 301);
170
+ }
171
+ // SSR
172
+ const response = await renderPage({
173
+ pathname: url.pathname,
174
+ newOrigin: url.origin,
175
+ hostname: url.hostname,
176
+ bypass: serverContext.shouldBypass(req),
177
+ });
178
+ if (opts.skewProtection) {
179
+ // Pins this browser to the deployment it loaded, so later chunk/data requests hit matching code.
180
+ const { deploymentId } = opts.skewProtection;
181
+ return withHeaders(response, (headers) => appendSetCookie(headers, "__vdpl", deploymentId, { httpOnly: false }));
182
+ }
183
+ return response;
184
+ },
185
+ };
186
+ }
@@ -1,5 +1,5 @@
1
- import { Manifest } from "vinxi/manifest";
2
- import { H3Event, RequestHeaders } from "vinxi/http";
1
+ import type { ServerAssets } from "./assets.js";
2
+ import { type RequestHeaders } from "./utils/request.js";
3
3
  import type { EDCacheConfig, EDConfig } from "../../node/project/config.js";
4
4
  import { TrackerTags } from "../lib/routing/types.js";
5
5
  import { QueryMonitor } from "../utils/query-monitor.js";
@@ -13,7 +13,7 @@ export type ServerContextArgs = {
13
13
  cacheConfig: EDCacheConfig;
14
14
  };
15
15
  export type ServerContextRuntime = {
16
- getManifest: (name: string) => Manifest;
16
+ assets: ServerAssets;
17
17
  };
18
18
  /**
19
19
  * Data returned from WordPress origin /_appdata route
@@ -53,7 +53,7 @@ export declare class ServerContext {
53
53
  bypass?: boolean;
54
54
  newOrigin?: string;
55
55
  }): Promise<ServerAppData>;
56
- extractRequestHeaders(req?: RequestHeaders): Partial<Record<import("vinxi/http").HTTPHeaderName, string | undefined>>;
56
+ extractRequestHeaders(req?: RequestHeaders): Record<string, string>;
57
57
  fetchNamedQuery(req: {
58
58
  name: string;
59
59
  bypass: boolean;
@@ -66,7 +66,7 @@ export declare class ServerContext {
66
66
  headers: RequestHeaders;
67
67
  }): Promise<Response>;
68
68
  get allowedCorsOrigins(): string[];
69
- shouldBypass(event: H3Event): boolean;
69
+ shouldBypass(req: Request): boolean;
70
70
  getCorsOrigin(originHeader: string): string | undefined;
71
71
  getCorsHeaders(origin: string): {
72
72
  "Access-Control-Allow-Methods"?: undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"server-context.d.ts","sourceRoot":"","sources":["../../../src/app/server/server-context.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"server-context.d.ts","sourceRoot":"","sources":["../../../src/app/server/server-context.ts"],"names":[],"mappings":"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"}
@@ -1,8 +1,8 @@
1
1
  import chalk from "chalk";
2
2
  import { inspect } from "node:util";
3
3
  import { parseURL, stringifyParsedURL, withQuery, withTrailingSlash } from "ufo";
4
- import { getCookie, getHeader } from "vinxi/http";
5
- import { fetchWP } from "../../node/utils/fetch-wp.js";
4
+ import { getCookie } from "./utils/request.js";
5
+ import { fetchOrigin as fetchFromOrigin } from "./utils/fetch-origin.js";
6
6
  import { QueryMonitor } from "../utils/query-monitor.js";
7
7
  import { filterHeader } from "./utils/headers.js";
8
8
  import { createUrlReplacer } from "./utils/replace-host.js";
@@ -78,18 +78,25 @@ export class ServerContext {
78
78
  const fetchOps = { ...opts };
79
79
  delete fetchOps.replaceUrls;
80
80
  delete fetchOps.newOrigin;
81
- const response = await fetchWP(url, {
81
+ const response = await fetchFromOrigin(url, {
82
82
  ...fetchOps,
83
83
  });
84
- if (!response.ok) {
85
- return response;
86
- }
87
- const headers = {};
84
+ // Only pass on allowed headers, for error responses too. The origin's connection headers
85
+ // (transfer-encoding, keep-alive etc.) are forbidden over HTTP/2, and fetch has already decoded the
86
+ // body, so content-length and content-encoding no longer apply.
87
+ const headers = new Headers();
88
88
  response.headers.forEach((value, key) => {
89
89
  if (filterHeader(key, PROXY_RESPONSE_HEADERS)) {
90
- headers[key] = value;
90
+ headers.append(key, value);
91
91
  }
92
92
  });
93
+ if (!response.ok) {
94
+ return new Response(response.body, {
95
+ status: response.status,
96
+ statusText: response.statusText,
97
+ headers,
98
+ });
99
+ }
93
100
  let text = await response.text();
94
101
  if (opts?.replaceUrls) {
95
102
  text = this.replaceUrls(text, opts.newOrigin);
@@ -343,8 +350,9 @@ export class ServerContext {
343
350
  const headers = {};
344
351
  if (req) {
345
352
  for (let key of PROXY_REQUEST_HEADERS) {
346
- if (req[key]) {
347
- headers[key] = req[key];
353
+ const value = req[key];
354
+ if (value) {
355
+ headers[key] = value;
348
356
  }
349
357
  }
350
358
  }
@@ -442,15 +450,15 @@ export class ServerContext {
442
450
  }
443
451
  return result;
444
452
  }
445
- shouldBypass(event) {
453
+ shouldBypass(req) {
446
454
  const bypassToken = process.env.VERCEL_BYPASS_TOKEN;
447
455
  if (!bypassToken)
448
456
  return false;
449
457
  const cookieName = "__prerender_bypass";
450
- if (getCookie(event, cookieName) === bypassToken) {
458
+ if (getCookie(req, cookieName) === bypassToken) {
451
459
  return true;
452
460
  }
453
- if (getHeader(event, "x-prerender-revalidate") === bypassToken) {
461
+ if (req.headers.get("x-prerender-revalidate") === bypassToken) {
454
462
  return true;
455
463
  }
456
464
  return false;
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Fetches from the WordPress origin, adding the eddev API key when origin protection is enabled.
3
+ *
4
+ * Uses the platform's own `fetch` (Node, Vercel, Cloudflare Workers), with normal TLS verification.
5
+ * Local's self-signed certificates are accepted in `eddev dev` and `eddev preview`, which disable TLS
6
+ * verification for the whole process (`NODE_TLS_REJECT_UNAUTHORIZED=0`).
7
+ *
8
+ * The CLI's `fetchWP` (undici, with certificate checks disabled) is deliberately not used here: undici
9
+ * doesn't work in the Workers runtime, and it disabled certificate checks for every request the
10
+ * production server made.
11
+ */
12
+ export declare function fetchOrigin(url: string | URL, init?: RequestInit): Promise<Response>;
13
+ //# sourceMappingURL=fetch-origin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetch-origin.d.ts","sourceRoot":"","sources":["../../../../src/app/server/utils/fetch-origin.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;GAUG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,EAAE,IAAI,GAAE,WAAgB,GAAG,OAAO,CAAC,QAAQ,CAAC,CAUxF"}
@@ -0,0 +1,21 @@
1
+ import { apiConfig } from "../../lib/runtime/apiConfig.js";
2
+ /**
3
+ * Fetches from the WordPress origin, adding the eddev API key when origin protection is enabled.
4
+ *
5
+ * Uses the platform's own `fetch` (Node, Vercel, Cloudflare Workers), with normal TLS verification.
6
+ * Local's self-signed certificates are accepted in `eddev dev` and `eddev preview`, which disable TLS
7
+ * verification for the whole process (`NODE_TLS_REJECT_UNAUTHORIZED=0`).
8
+ *
9
+ * The CLI's `fetchWP` (undici, with certificate checks disabled) is deliberately not used here: undici
10
+ * doesn't work in the Workers runtime, and it disabled certificate checks for every request the
11
+ * production server made.
12
+ */
13
+ export function fetchOrigin(url, init = {}) {
14
+ const headers = new Headers(init.headers);
15
+ // Runtime environment first, then the key baked in at build time (see the generated context.ts)
16
+ const apiKey = (typeof process !== "undefined" ? process.env?.SITE_API_KEY : undefined) || apiConfig.apiKey;
17
+ if (apiKey) {
18
+ headers.set("x-ed-api-key", apiKey);
19
+ }
20
+ return fetch(url, { ...init, headers });
21
+ }
@@ -0,0 +1,20 @@
1
+ import { serialize as serializeCookie } from "cookie-es";
2
+ /** Request headers as a plain object with lowercase keys. */
3
+ export type RequestHeaders = Record<string, string | undefined>;
4
+ /**
5
+ * The request URL as seen by the visitor. Honours `x-forwarded-proto: https` from a trusted proxy
6
+ * (Vercel, Cloudflare, the local dev HTTPS redirect), matching h3 v1's `getRequestURL` default.
7
+ */
8
+ export declare function getRequestURL(req: Request): URL;
9
+ /** The raw path and query string of a request, without decoding. */
10
+ export declare function getRawPath(req: Request): string;
11
+ export declare function getRequestHeaders(req: Request): RequestHeaders;
12
+ export declare function getCookie(req: Request, name: string): string | undefined;
13
+ export type CookieOptions = Parameters<typeof serializeCookie>[2];
14
+ /** Appends a `Set-Cookie` header. Defaults the cookie path to `/`. */
15
+ export declare function appendSetCookie(headers: Headers, name: string, value: string, options?: CookieOptions): void;
16
+ /** Request headers suitable for forwarding to another origin. */
17
+ export declare function getProxyRequestHeaders(req: Request): Record<string, string>;
18
+ /** Returns a copy of the response with additional headers, for responses whose headers may be immutable. */
19
+ export declare function withHeaders(response: Response, apply: (headers: Headers) => void): Response;
20
+ //# sourceMappingURL=request.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request.d.ts","sourceRoot":"","sources":["../../../../src/app/server/utils/request.ts"],"names":[],"mappings":"AAAA,OAAO,EAAyB,SAAS,IAAI,eAAe,EAAE,MAAM,WAAW,CAAA;AAE/E,6DAA6D;AAC7D,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAA;AAE/D;;;GAGG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,OAAO,GAAG,GAAG,CAM/C;AAED,oEAAoE;AACpE,wBAAgB,UAAU,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAG/C;AAED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,OAAO,GAAG,cAAc,CAM9D;AAED,wBAAgB,SAAS,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAIxE;AAED,MAAM,MAAM,aAAa,GAAG,UAAU,CAAC,OAAO,eAAe,CAAC,CAAC,CAAC,CAAC,CAAA;AAEjE,sEAAsE;AACtE,wBAAgB,eAAe,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,QAEzG;AAcD,iEAAiE;AACjE,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAM3E;AAED,4GAA4G;AAC5G,wBAAgB,WAAW,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,GAAG,QAAQ,CAI3F"}
@@ -0,0 +1,60 @@
1
+ import { parse as parseCookies, serialize as serializeCookie } from "cookie-es";
2
+ /**
3
+ * The request URL as seen by the visitor. Honours `x-forwarded-proto: https` from a trusted proxy
4
+ * (Vercel, Cloudflare, the local dev HTTPS redirect), matching h3 v1's `getRequestURL` default.
5
+ */
6
+ export function getRequestURL(req) {
7
+ const url = new URL(req.url);
8
+ if (req.headers.get("x-forwarded-proto") === "https") {
9
+ url.protocol = "https:";
10
+ }
11
+ return url;
12
+ }
13
+ /** The raw path and query string of a request, without decoding. */
14
+ export function getRawPath(req) {
15
+ const url = new URL(req.url);
16
+ return req.url.slice(url.origin.length) || "/";
17
+ }
18
+ export function getRequestHeaders(req) {
19
+ const headers = {};
20
+ req.headers.forEach((value, name) => {
21
+ headers[name] = value;
22
+ });
23
+ return headers;
24
+ }
25
+ export function getCookie(req, name) {
26
+ const header = req.headers.get("cookie");
27
+ if (!header)
28
+ return undefined;
29
+ return parseCookies(header)[name];
30
+ }
31
+ /** Appends a `Set-Cookie` header. Defaults the cookie path to `/`. */
32
+ export function appendSetCookie(headers, name, value, options = {}) {
33
+ headers.append("set-cookie", serializeCookie(name, value, { path: "/", ...options }));
34
+ }
35
+ /** Headers which shouldn't be forwarded when proxying a request (same list as h3 v1). */
36
+ const IGNORED_PROXY_HEADERS = new Set([
37
+ "transfer-encoding",
38
+ "accept-encoding",
39
+ "connection",
40
+ "keep-alive",
41
+ "upgrade",
42
+ "expect",
43
+ "host",
44
+ "accept",
45
+ ]);
46
+ /** Request headers suitable for forwarding to another origin. */
47
+ export function getProxyRequestHeaders(req) {
48
+ const headers = {};
49
+ req.headers.forEach((value, name) => {
50
+ if (!IGNORED_PROXY_HEADERS.has(name))
51
+ headers[name] = value;
52
+ });
53
+ return headers;
54
+ }
55
+ /** Returns a copy of the response with additional headers, for responses whose headers may be immutable. */
56
+ export function withHeaders(response, apply) {
57
+ const headers = new Headers(response.headers);
58
+ apply(headers);
59
+ return new Response(response.body, { status: response.status, statusText: response.statusText, headers });
60
+ }
@@ -1,13 +1,17 @@
1
1
  import { Worker } from "node:worker_threads";
2
+ import type { SPATarget } from "../compiler/bundler.spa.js";
2
3
  import type { StatefulLog } from "../utils/stateful-log.js";
3
- type WorkerMode = "admin" | "frontend" | "graphql" | "serverless";
4
+ type WorkerMode = "spa" | "graphql" | "serverless";
5
+ type WorkerOptions = {
6
+ log: StatefulLog<any>;
7
+ mode: WorkerMode;
8
+ verbose: boolean;
9
+ /** For the `spa` mode: which bundles to build */
10
+ spaTargets?: SPATarget[];
11
+ };
4
12
  export declare class CLIWorker {
5
13
  worker: Worker;
6
- constructor({ log, mode, verbose }: {
7
- log: StatefulLog<any>;
8
- mode: WorkerMode;
9
- verbose: boolean;
10
- });
14
+ constructor({ log, mode, verbose, spaTargets }: WorkerOptions);
11
15
  shutdown(): Promise<void>;
12
16
  }
13
17
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"cli-worker.d.ts","sourceRoot":"","sources":["../../../src/node/cli/cli-worker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAwC,MAAM,qBAAqB,CAAA;AAClF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAA;AAG3D,KAAK,UAAU,GAAG,OAAO,GAAG,UAAU,GAAG,SAAS,GAAG,YAAY,CAAA;AAEjE,qBAAa,SAAS;IACpB,MAAM,EAAE,MAAM,CAAA;gBACF,EAAE,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE;QAAE,GAAG,EAAE,WAAW,CAAC,GAAG,CAAC,CAAC;QAAC,IAAI,EAAE,UAAU,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE;IAkC3F,QAAQ;CAGf"}
1
+ {"version":3,"file":"cli-worker.d.ts","sourceRoot":"","sources":["../../../src/node/cli/cli-worker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAwC,MAAM,qBAAqB,CAAA;AAClF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAA;AAC3D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAA;AAG3D,KAAK,UAAU,GAAG,KAAK,GAAG,SAAS,GAAG,YAAY,CAAA;AAElD,KAAK,aAAa,GAAG;IACnB,GAAG,EAAE,WAAW,CAAC,GAAG,CAAC,CAAA;IACrB,IAAI,EAAE,UAAU,CAAA;IAChB,OAAO,EAAE,OAAO,CAAA;IAChB,iDAAiD;IACjD,UAAU,CAAC,EAAE,SAAS,EAAE,CAAA;CACzB,CAAA;AAED,qBAAa,SAAS;IACpB,MAAM,EAAE,MAAM,CAAA;gBACF,EAAE,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE,EAAE,aAAa;IAmCvD,QAAQ;CAGf"}
@@ -2,11 +2,12 @@ import { Worker, isMainThread, parentPort, workerData } from "node:worker_thread
2
2
  import { configureCliMode } from "./cli-mode.js";
3
3
  export class CLIWorker {
4
4
  worker;
5
- constructor({ log, mode, verbose }) {
5
+ constructor({ log, mode, verbose, spaTargets }) {
6
6
  const worker = new Worker(new URL(import.meta.url), {
7
7
  workerData: {
8
8
  mode,
9
9
  verbose,
10
+ spaTargets,
10
11
  },
11
12
  stdout: true,
12
13
  stderr: true,
@@ -86,23 +87,15 @@ if (!isMainThread) {
86
87
  parentPort?.postMessage(JSON.stringify({ type: "log", log: serializeLogData(log) }));
87
88
  });
88
89
  }
89
- if (mode === "admin") {
90
- const { AdminBundler, adminLog } = await import("../compiler/bundler.admin.js");
91
- const bundler = new AdminBundler(project, {
90
+ if (mode === "spa") {
91
+ const { SPABundler, spaLog } = await import("../compiler/bundler.spa.js");
92
+ const bundler = new SPABundler(project, {
92
93
  mode: "development",
93
94
  watch: true,
95
+ targets: workerData.spaTargets,
94
96
  });
95
97
  bundler.start();
96
- pipeLog(adminLog);
97
- }
98
- else if (mode === "frontend") {
99
- const { FrontendBundler, frontendLog } = await import("../compiler/bundler.frontend.js");
100
- const bundler = new FrontendBundler(project, {
101
- mode: "development",
102
- watch: true,
103
- });
104
- bundler.start();
105
- pipeLog(frontendLog);
98
+ pipeLog(spaLog);
106
99
  }
107
100
  else if (mode === "graphql") {
108
101
  const { GraphQLGenerator, graphqlLog } = await import("../graphql/graphql-codegen.js");