@cedarjs/vite 4.1.1-next.1 → 4.1.1-next.55

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 (52) hide show
  1. package/dist/apiDevMiddleware.d.ts +15 -0
  2. package/dist/apiDevMiddleware.d.ts.map +1 -0
  3. package/dist/{apiDevServer.js → apiDevMiddleware.js} +95 -107
  4. package/dist/build/build.d.ts +1 -1
  5. package/dist/build/build.d.ts.map +1 -1
  6. package/dist/build/build.js +2 -0
  7. package/dist/buildApp.d.ts +15 -0
  8. package/dist/buildApp.d.ts.map +1 -0
  9. package/dist/buildApp.js +150 -0
  10. package/dist/buildUDApiServer.d.ts +7 -5
  11. package/dist/buildUDApiServer.d.ts.map +1 -1
  12. package/dist/buildUDApiServer.js +8 -26
  13. package/dist/cedar-unified-dev.js +59 -5
  14. package/dist/cjs/{apiDevServer.js → apiDevMiddleware.js} +102 -110
  15. package/dist/cjs/build/build.js +3 -0
  16. package/dist/cjs/buildApp.js +181 -0
  17. package/dist/cjs/buildUDApiServer.js +8 -26
  18. package/dist/cjs/cedar-unified-dev.js +59 -5
  19. package/dist/cjs/index.js +3 -3
  20. package/dist/cjs/plugins/vite-plugin-cedar-cjs-compat.js +341 -0
  21. package/dist/cjs/plugins/vite-plugin-cedar-universal-deploy.js +114 -19
  22. package/dist/cjs/plugins/vite-plugin-cedar-wait-for-api-server.js +2 -1
  23. package/dist/cjs/ud-handlers/catch-all.js +65 -0
  24. package/dist/cjs/ud-handlers/function.js +47 -0
  25. package/dist/cjs/ud-handlers/graphql.js +59 -0
  26. package/dist/index.d.ts +1 -1
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js +2 -2
  29. package/dist/plugins/vite-plugin-cedar-cjs-compat.d.ts +23 -0
  30. package/dist/plugins/vite-plugin-cedar-cjs-compat.d.ts.map +1 -0
  31. package/dist/plugins/vite-plugin-cedar-cjs-compat.js +307 -0
  32. package/dist/plugins/vite-plugin-cedar-universal-deploy.d.ts.map +1 -1
  33. package/dist/plugins/vite-plugin-cedar-universal-deploy.js +105 -20
  34. package/dist/plugins/vite-plugin-cedar-wait-for-api-server.d.ts.map +1 -1
  35. package/dist/plugins/vite-plugin-cedar-wait-for-api-server.js +2 -1
  36. package/dist/ud-handlers/catch-all.d.ts +15 -0
  37. package/dist/ud-handlers/catch-all.d.ts.map +1 -0
  38. package/dist/ud-handlers/catch-all.js +41 -0
  39. package/dist/ud-handlers/function.d.ts +5 -0
  40. package/dist/ud-handlers/function.d.ts.map +1 -0
  41. package/dist/ud-handlers/function.js +23 -0
  42. package/dist/ud-handlers/graphql.d.ts +7 -0
  43. package/dist/ud-handlers/graphql.d.ts.map +1 -0
  44. package/dist/ud-handlers/graphql.js +35 -0
  45. package/package.json +52 -23
  46. package/LICENSE +0 -21
  47. package/dist/apiDevServer.d.ts +0 -18
  48. package/dist/apiDevServer.d.ts.map +0 -1
  49. package/dist/cjs/plugins/vite-plugin-cedar-dev-dispatcher.js +0 -223
  50. package/dist/plugins/vite-plugin-cedar-dev-dispatcher.d.ts +0 -3
  51. package/dist/plugins/vite-plugin-cedar-dev-dispatcher.d.ts.map +0 -1
  52. package/dist/plugins/vite-plugin-cedar-dev-dispatcher.js +0 -189
@@ -0,0 +1,15 @@
1
+ import type { ViteDevServer } from 'vite';
2
+ export declare function loadApiFunctions(viteServer: ViteDevServer): Promise<void>;
3
+ export declare function createApiViteServer(): Promise<ViteDevServer>;
4
+ export declare function setupHmrHandlers(viteServer: ViteDevServer): void;
5
+ /**
6
+ * Creates a fetch-native handler for API requests.
7
+ * Routes GraphQL to Yoga and Lambda functions to their handlers.
8
+ */
9
+ export declare function createApiFetchHandler(): (request: Request) => Promise<Response>;
10
+ export declare function startApiDevMiddleware(): Promise<{
11
+ viteServer: ViteDevServer;
12
+ close: () => Promise<void>;
13
+ handler: (request: Request) => Promise<Response>;
14
+ }>;
15
+ //# sourceMappingURL=apiDevMiddleware.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apiDevMiddleware.d.ts","sourceRoot":"","sources":["../src/apiDevMiddleware.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAc,aAAa,EAAE,MAAM,MAAM,CAAA;AA2BrD,wBAAsB,gBAAgB,CAAC,UAAU,EAAE,aAAa,iBAe/D;AA8GD,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,aAAa,CAAC,CAuElE;AA0BD,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,aAAa,GAAG,IAAI,CA0EhE;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,KAIrB,SAAS,OAAO,KAAG,OAAO,CAAC,QAAQ,CAAC,CAoEnD;AAED,wBAAsB,qBAAqB,IAAI,OAAO,CAAC;IACrD,UAAU,EAAE,aAAa,CAAA;IACzB,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IAC1B,OAAO,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAA;CACjD,CAAC,CAcD"}
@@ -1,12 +1,9 @@
1
1
  import { glob } from "node:fs/promises";
2
2
  import path from "node:path";
3
3
  import { pathToFileURL } from "node:url";
4
- import fastifyUrlData from "@fastify/url-data";
5
4
  import ansis from "ansis";
6
- import fastify from "fastify";
7
- import fastifyRawBody from "fastify-raw-body";
8
- import { createServer as createViteServer, normalizePath } from "vite";
9
- import { requestHandler } from "@cedarjs/api-server/requestHandlers";
5
+ import { normalizePath } from "vite";
6
+ import { buildCedarContext, wrapLegacyHandler } from "@cedarjs/api/runtime";
10
7
  import {
11
8
  getApiSideBabelPlugins,
12
9
  transformWithBabel
@@ -56,13 +53,6 @@ async function internalLoadApiFunctions(viteServer) {
56
53
  } catch {
57
54
  srcFunctions = [];
58
55
  }
59
- const graphqlFunctionIndex = srcFunctions.findIndex(
60
- (f) => path.basename(f).startsWith("graphql.")
61
- );
62
- if (graphqlFunctionIndex > 0) {
63
- const [graphqlFn] = srcFunctions.splice(graphqlFunctionIndex, 1);
64
- srcFunctions.unshift(graphqlFn);
65
- }
66
56
  console.log(ansis.dim.italic("Importing Server Functions... "));
67
57
  const tsImport = Date.now();
68
58
  let extractedGraphqlOptions = null;
@@ -71,24 +61,33 @@ async function internalLoadApiFunctions(viteServer) {
71
61
  const routeName = path.basename(fnPath).replace(/\.(ts|tsx|js|jsx)$/, "");
72
62
  try {
73
63
  const mod = await viteServer.ssrLoadModule(pathToFileURL(fnPath).href);
74
- const handler = (() => {
64
+ const cedarHandler = (() => {
65
+ if ("handleRequest" in mod) {
66
+ return mod.handleRequest;
67
+ }
68
+ if ("default" in mod && mod.default && "handleRequest" in mod.default) {
69
+ return mod.default.handleRequest;
70
+ }
71
+ let legacyHandler;
75
72
  if ("handler" in mod) {
76
- return mod.handler;
73
+ legacyHandler = mod.handler;
74
+ } else if ("default" in mod && mod.default && "handler" in mod.default) {
75
+ legacyHandler = mod.default.handler;
77
76
  }
78
- if ("default" in mod && mod.default && "handler" in mod.default) {
79
- return mod.default.handler;
77
+ if (legacyHandler) {
78
+ return wrapLegacyHandler(legacyHandler);
80
79
  }
81
80
  return void 0;
82
81
  })();
83
- if (handler) {
84
- LAMBDA_FUNCTIONS[routeName] = handler;
82
+ if (cedarHandler) {
83
+ LAMBDA_FUNCTIONS[routeName] = cedarHandler;
85
84
  console.log(
86
85
  ansis.magenta("/" + routeName),
87
86
  ansis.dim.italic(Date.now() - ts + " ms")
88
87
  );
89
88
  } else {
90
89
  console.warn(
91
- `[apiDevServer] No handler export found in function: ${fnPath}`
90
+ `[apiDevMiddleware] No handler or handleRequest export found in function: ${fnPath}`
92
91
  );
93
92
  }
94
93
  if (routeName === "graphql" && "__rw_graphqlOptions" in mod) {
@@ -97,7 +96,7 @@ async function internalLoadApiFunctions(viteServer) {
97
96
  } catch (err) {
98
97
  viteServer.ssrFixStacktrace(err);
99
98
  console.error(
100
- `[apiDevServer] Failed to load function "${routeName}" from ${fnPath}:`,
99
+ `[apiDevMiddleware] Failed to load function "${routeName}" from ${fnPath}:`,
101
100
  err
102
101
  );
103
102
  }
@@ -106,56 +105,29 @@ async function internalLoadApiFunctions(viteServer) {
106
105
  if (extractedGraphqlOptions) {
107
106
  const { yoga } = await createGraphQLYoga(extractedGraphqlOptions);
108
107
  graphqlYoga = yoga;
108
+ } else {
109
+ graphqlYoga = null;
109
110
  }
110
111
  console.log(
111
112
  ansis.dim.italic("...Done importing in " + (Date.now() - tsImport) + " ms")
112
113
  );
113
114
  }
114
- function createFetchRequestFromFastify(req) {
115
- const requestBody = req.method === "GET" || req.method === "HEAD" ? void 0 : typeof req.body === "string" ? req.body : req.body ? JSON.stringify(req.body) : void 0;
116
- const href = `${req.protocol}://${req.host}${req.raw.url ?? "/"}`;
117
- return new Request(href, {
118
- method: req.method,
119
- headers: req.headers,
120
- body: requestBody
121
- });
122
- }
123
- async function startApiDevServer(port) {
115
+ async function createApiViteServer() {
124
116
  const cedarPaths = getPaths();
125
117
  const cedarConfig = getConfig();
126
- const apiPort = port || cedarConfig.api.port || 8911;
127
- const apiHost = cedarConfig.api.host || "::";
128
118
  const isEsm = projectSideIsEsm("api");
129
119
  const normalizedBase = normalizePath(cedarPaths.base);
130
- const normalizedApiSrc = normalizePath(cedarPaths.api.src);
131
- const normalizedApiBase = normalizePath(cedarPaths.api.base);
132
- const viteServer = await createViteDevServer(
133
- cedarPaths,
134
- cedarConfig,
135
- isEsm,
136
- normalizedBase
137
- );
138
- console.log(ansis.dim.italic("Starting API dev server..."));
139
- await loadApiFunctions(viteServer);
140
- setupHmrHandlers(viteServer, normalizedApiSrc, normalizedApiBase);
141
- const app = await createFastifyApp(apiPort, apiHost);
142
- const close = async () => {
143
- await app.close();
144
- await viteServer.close();
145
- };
146
- return { viteServer, close };
147
- }
148
- async function createViteDevServer(cedarPaths, cedarConfig, projectIsEsm, normalizedBase) {
149
120
  const babelPlugins = getApiSideBabelPlugins({
150
121
  openTelemetry: (cedarConfig.experimental?.opentelemetry?.enabled ?? false) && (cedarConfig.experimental?.opentelemetry?.wrapApi ?? false),
151
- projectIsEsm
122
+ projectIsEsm: isEsm
152
123
  });
153
124
  const workspacePkgSourceMap = Object.fromEntries(
154
125
  Object.entries(getWorkspacePackageAliases(cedarPaths, cedarConfig)).map(
155
126
  ([name, sourceFile]) => [name, normalizePath(sourceFile)]
156
127
  )
157
128
  );
158
- const viteServer = await createViteServer({
129
+ const { createServer: createViteServer } = await import("vite");
130
+ return createViteServer({
159
131
  configFile: false,
160
132
  root: cedarPaths.api.base,
161
133
  appType: "custom",
@@ -165,10 +137,6 @@ async function createViteDevServer(cedarPaths, cedarConfig, projectIsEsm, normal
165
137
  middlewareMode: true
166
138
  },
167
139
  resolve: {
168
- // Map workspace package names directly to their TypeScript source entry
169
- // files. This is processed by Vite's built-in alias plugin (enforce:
170
- // 'pre') which runs before vite:resolve and correctly intercepts imports
171
- // in the SSR module runner context.
172
140
  alias: workspacePkgSourceMap
173
141
  },
174
142
  plugins: [
@@ -203,7 +171,6 @@ async function createViteDevServer(cedarPaths, cedarConfig, projectIsEsm, normal
203
171
  }
204
172
  ]
205
173
  });
206
- return viteServer;
207
174
  }
208
175
  function invalidateApiModules(viteServer, normalizedApiSrc) {
209
176
  const invalidated = /* @__PURE__ */ new Set();
@@ -223,7 +190,10 @@ function invalidateApiModules(viteServer, normalizedApiSrc) {
223
190
  }
224
191
  }
225
192
  }
226
- function setupHmrHandlers(viteServer, normalizedApiSrc, normalizedApiBase) {
193
+ function setupHmrHandlers(viteServer) {
194
+ const cedarPaths = getPaths();
195
+ const normalizedApiSrc = normalizePath(cedarPaths.api.src);
196
+ const normalizedApiBase = normalizePath(cedarPaths.api.base);
227
197
  viteServer.watcher.on("change", async (filePath) => {
228
198
  const normalizedFilePath = normalizePath(filePath);
229
199
  if (!normalizedFilePath.startsWith(normalizedApiSrc)) {
@@ -276,60 +246,78 @@ function setupHmrHandlers(viteServer, normalizedApiSrc, normalizedApiBase) {
276
246
  await loadApiFunctions(viteServer);
277
247
  });
278
248
  }
279
- async function createFastifyApp(apiPort, apiHost) {
280
- const logLevel = process.env.NODE_ENV === "development" ? "debug" : "info";
281
- const app = fastify({ logger: { level: logLevel } });
282
- await app.register(fastifyRawBody);
283
- app.register(fastifyUrlData);
284
- app.addContentTypeParser(
285
- ["application/x-www-form-urlencoded", "multipart/form-data"],
286
- { parseAs: "string" },
287
- app.defaultTextParser
288
- );
289
- const lambdaRequestHandler = async (req, reply) => {
290
- const { routeName } = req.params;
249
+ function createApiFetchHandler() {
250
+ const cedarConfig = getConfig();
251
+ const apiUrlPrefix = cedarConfig.web.apiUrl.replace(/\/$/, "");
252
+ return async (request) => {
253
+ const url = new URL(request.url);
254
+ let pathname = url.pathname;
255
+ if (pathname.startsWith(apiUrlPrefix + "/")) {
256
+ pathname = pathname.slice(apiUrlPrefix.length);
257
+ } else if (pathname === apiUrlPrefix) {
258
+ pathname = "/";
259
+ }
260
+ if (pathname === "/graphql" || pathname.startsWith("/graphql/")) {
261
+ if (!graphqlYoga) {
262
+ return new Response(
263
+ JSON.stringify({ error: "GraphQL Yoga instance not initialized" }),
264
+ { status: 503, headers: { "Content-Type": "application/json" } }
265
+ );
266
+ }
267
+ const yoga = graphqlYoga;
268
+ return getAsyncStoreInstance().run(/* @__PURE__ */ new Map(), async () => {
269
+ return yoga.handle(request, { request });
270
+ });
271
+ }
272
+ const match = pathname.match(/^\/([^/]+)(?:\/.*)?$/);
273
+ if (!match) {
274
+ return new Response("Not Found", { status: 404 });
275
+ }
276
+ const routeName = match[1];
291
277
  const handler = LAMBDA_FUNCTIONS[routeName];
292
278
  if (!handler) {
293
- const errorMessage = `Function "${routeName}" was not found.`;
294
- req.log.error(errorMessage);
295
- reply.status(404);
296
- reply.send({
297
- error: errorMessage,
298
- availableFunctions: Object.keys(LAMBDA_FUNCTIONS)
279
+ return new Response(
280
+ JSON.stringify({
281
+ error: `Function "${routeName}" was not found.`,
282
+ availableFunctions: Object.keys(LAMBDA_FUNCTIONS)
283
+ }),
284
+ { status: 404, headers: { "Content-Type": "application/json" } }
285
+ );
286
+ }
287
+ try {
288
+ const ctx = await buildCedarContext(request, {
289
+ params: { routeName }
299
290
  });
300
- return;
291
+ return await handler(request, ctx);
292
+ } catch (err) {
293
+ console.error(
294
+ `[apiDevMiddleware] Error handling function "${routeName}":`,
295
+ err
296
+ );
297
+ return new Response(
298
+ JSON.stringify({
299
+ error: err instanceof Error ? err.message : "Internal Server Error"
300
+ }),
301
+ { status: 500, headers: { "Content-Type": "application/json" } }
302
+ );
301
303
  }
302
- return requestHandler(req, reply, handler);
303
304
  };
304
- const graphqlHandler = async (req, reply) => {
305
- if (!graphqlYoga) {
306
- return reply.status(503).send({ error: "GraphQL Yoga instance not initialized" });
307
- }
308
- const request = createFetchRequestFromFastify(req);
309
- const yoga = graphqlYoga;
310
- const response = await getAsyncStoreInstance().run(/* @__PURE__ */ new Map(), async () => {
311
- return yoga.handle(request, { req, reply });
312
- });
313
- return response;
305
+ }
306
+ async function startApiDevMiddleware() {
307
+ const viteServer = await createApiViteServer();
308
+ console.log(ansis.dim.italic("Starting API dev server..."));
309
+ await loadApiFunctions(viteServer);
310
+ setupHmrHandlers(viteServer);
311
+ const close = async () => {
312
+ await viteServer.close();
314
313
  };
315
- app.all("/graphql", graphqlHandler);
316
- app.all("/graphql/*", graphqlHandler);
317
- app.all("/:routeName", lambdaRequestHandler);
318
- app.all("/:routeName/*", lambdaRequestHandler);
319
- app.addHook("onListen", (done) => {
320
- const addr = app.server.address();
321
- const listenPort = addr && typeof addr === "object" ? addr.port : apiPort;
322
- console.log(
323
- `API dev server listening at ${ansis.magenta(`http://localhost:${listenPort}/`)}`
324
- );
325
- console.log(
326
- `GraphQL endpoint at ${ansis.magenta(`http://localhost:${listenPort}/graphql`)}`
327
- );
328
- done();
329
- });
330
- await app.listen({ port: apiPort, host: apiHost });
331
- return app;
314
+ const handler = createApiFetchHandler();
315
+ return { viteServer, close, handler };
332
316
  }
333
317
  export {
334
- startApiDevServer
318
+ createApiFetchHandler,
319
+ createApiViteServer,
320
+ loadApiFunctions,
321
+ setupHmrHandlers,
322
+ startApiDevMiddleware
335
323
  };
@@ -1,3 +1,4 @@
1
+ export { buildCedarApp } from '../buildApp.js';
1
2
  interface BuildOptions {
2
3
  verbose?: boolean;
3
4
  }
@@ -6,5 +7,4 @@ interface BuildOptions {
6
7
  * because we want to set the process.cwd to web.base
7
8
  */
8
9
  export declare const buildWeb: ({ verbose }: BuildOptions) => Promise<import("rollup").RollupOutput | import("rollup").RollupOutput[] | import("rollup").RollupWatcher>;
9
- export {};
10
10
  //# sourceMappingURL=build.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/build/build.ts"],"names":[],"mappings":"AAEA,UAAU,YAAY;IACpB,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAED;;;GAGG;AACH,eAAO,MAAM,QAAQ,GAAU,aAAa,YAAY,8GAoBvD,CAAA"}
1
+ {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/build/build.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAE9C,UAAU,YAAY;IACpB,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAED;;;GAGG;AACH,eAAO,MAAM,QAAQ,GAAU,aAAa,YAAY,8GAoBvD,CAAA"}
@@ -1,4 +1,5 @@
1
1
  import { getPaths } from "@cedarjs/project-config";
2
+ import { buildCedarApp } from "../buildApp.js";
2
3
  const buildWeb = async ({ verbose }) => {
3
4
  const { build } = await import("vite");
4
5
  const viteConfig = getPaths().web.viteConfig;
@@ -17,5 +18,6 @@ const buildWeb = async ({ verbose }) => {
17
18
  });
18
19
  };
19
20
  export {
21
+ buildCedarApp,
20
22
  buildWeb
21
23
  };
@@ -0,0 +1,15 @@
1
+ export interface BuildCedarAppOptions {
2
+ verbose?: boolean;
3
+ workspace?: string[];
4
+ }
5
+ /**
6
+ * Unified build for Cedar apps using Vite's builder API.
7
+ *
8
+ * Declares `client` and `api` environments and builds them in a single
9
+ * orchestrated pass. The web client is built from the project's web Vite
10
+ * config. The API is built as an SSR environment with Babel transforms and
11
+ * `src/` import redirection so it resolves correctly even though the builder
12
+ * root is the web source directory.
13
+ */
14
+ export declare function buildCedarApp({ verbose, workspace, }?: BuildCedarAppOptions): Promise<void>;
15
+ //# sourceMappingURL=buildApp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"buildApp.d.ts","sourceRoot":"","sources":["../src/buildApp.ts"],"names":[],"mappings":"AA4BA,MAAM,WAAW,oBAAoB;IACnC,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAA;CACrB;AAED;;;;;;;;GAQG;AACH,wBAAsB,aAAa,CAAC,EAClC,OAAe,EACf,SAA0B,GAC3B,GAAE,oBAAyB,iBA+J3B"}
@@ -0,0 +1,150 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { createBuilder, normalizePath } from "vite";
4
+ import {
5
+ getApiSideBabelPlugins,
6
+ transformWithBabel
7
+ } from "@cedarjs/babel-config";
8
+ import { findApiFiles } from "@cedarjs/internal/dist/files.js";
9
+ import { getConfig, getPaths, projectSideIsEsm } from "@cedarjs/project-config";
10
+ import { getWorkspacePackageAliases } from "./lib/workspacePackageAliases.js";
11
+ function resolveWithExtensions(id) {
12
+ if (fs.existsSync(id)) {
13
+ return id;
14
+ }
15
+ for (const ext of [".js", ".ts", ".jsx", ".tsx", ".mjs", ".mts"]) {
16
+ const withExt = id + ext;
17
+ if (fs.existsSync(withExt)) {
18
+ return withExt;
19
+ }
20
+ }
21
+ return id;
22
+ }
23
+ async function buildCedarApp({
24
+ verbose = false,
25
+ workspace = ["api", "web"]
26
+ } = {}) {
27
+ const cedarPaths = getPaths();
28
+ const cedarConfig = getConfig();
29
+ const environments = {};
30
+ if (workspace.includes("web")) {
31
+ environments.client = {
32
+ build: {
33
+ outDir: cedarPaths.web.dist
34
+ }
35
+ };
36
+ }
37
+ if (workspace.includes("api")) {
38
+ const isEsm = projectSideIsEsm("api");
39
+ const format = isEsm ? "es" : "cjs";
40
+ const apiFiles = findApiFiles();
41
+ const input = {};
42
+ for (const f of apiFiles) {
43
+ const key = path.relative(cedarPaths.api.src, f).replace(/\.(ts|tsx|mts|js|jsx|mjs)$/, "");
44
+ input[key] = f;
45
+ }
46
+ environments.api = {
47
+ build: {
48
+ ssr: true,
49
+ sourcemap: true,
50
+ outDir: cedarPaths.api.dist,
51
+ emptyOutDir: true,
52
+ rollupOptions: {
53
+ input,
54
+ output: {
55
+ format,
56
+ preserveModules: true,
57
+ preserveModulesRoot: cedarPaths.api.src,
58
+ entryFileNames: "[name].js"
59
+ },
60
+ external: (id) => {
61
+ if (id.startsWith("node:")) {
62
+ return true;
63
+ }
64
+ if (!id.startsWith(".") && !path.isAbsolute(id)) {
65
+ return true;
66
+ }
67
+ return false;
68
+ }
69
+ }
70
+ }
71
+ };
72
+ }
73
+ const babelPlugins = workspace.includes("api") ? getApiSideBabelPlugins({
74
+ openTelemetry: (cedarConfig.experimental?.opentelemetry?.enabled ?? false) && (cedarConfig.experimental?.opentelemetry?.wrapApi ?? false),
75
+ projectIsEsm: projectSideIsEsm("api")
76
+ }) : null;
77
+ const workspacePkgSourceMap = workspace.includes("api") ? Object.fromEntries(
78
+ Object.entries(getWorkspacePackageAliases(cedarPaths, cedarConfig)).map(
79
+ ([name, sourceFile]) => [name, normalizePath(sourceFile)]
80
+ )
81
+ ) : {};
82
+ const plugins = [
83
+ {
84
+ name: "cedar-build-app-cleanup",
85
+ configResolved(config) {
86
+ if (!workspace.includes("web") && config.environments.client) {
87
+ delete config.environments.client;
88
+ }
89
+ if (!environments.ssr && config.environments.ssr) {
90
+ delete config.environments.ssr;
91
+ }
92
+ }
93
+ }
94
+ ];
95
+ if (workspace.includes("api")) {
96
+ plugins.push({
97
+ name: "cedar-api-src-redirect",
98
+ enforce: "pre",
99
+ resolveId(id, importer) {
100
+ if (!importer?.startsWith(cedarPaths.api.src)) {
101
+ return null;
102
+ }
103
+ if (id.startsWith("src/")) {
104
+ return resolveWithExtensions(
105
+ path.join(cedarPaths.api.src, id.slice(4))
106
+ );
107
+ }
108
+ return null;
109
+ }
110
+ });
111
+ if (babelPlugins) {
112
+ plugins.push({
113
+ name: "cedar-vite-api-babel-transform",
114
+ async transform(_code, id) {
115
+ if (!/\.(js|ts|tsx|jsx)$/.test(id)) {
116
+ return null;
117
+ }
118
+ if (id.includes("node_modules")) {
119
+ return null;
120
+ }
121
+ if (!normalizePath(id).startsWith(normalizePath(cedarPaths.api.base))) {
122
+ return null;
123
+ }
124
+ const transformedCode = await transformWithBabel(id, babelPlugins);
125
+ if (transformedCode?.code) {
126
+ return {
127
+ code: transformedCode.code,
128
+ map: transformedCode.map ?? null
129
+ };
130
+ }
131
+ return null;
132
+ }
133
+ });
134
+ }
135
+ }
136
+ const builder = await createBuilder({
137
+ configFile: cedarPaths.web.viteConfig,
138
+ envFile: false,
139
+ logLevel: verbose ? "info" : "warn",
140
+ environments,
141
+ resolve: {
142
+ alias: workspacePkgSourceMap
143
+ },
144
+ plugins
145
+ });
146
+ return builder.buildApp();
147
+ }
148
+ export {
149
+ buildCedarApp
150
+ };
@@ -3,13 +3,15 @@ export interface BuildUDApiServerOptions {
3
3
  apiRootPath?: string;
4
4
  }
5
5
  /**
6
- * Builds the API server Universal Deploy Node entry using Vite.
6
+ * Builds the API server Universal Deploy entry using Vite.
7
7
  *
8
8
  * Runs a Vite server build that:
9
- * 1. Installs `cedarUniversalDeployPlugin()` to register `virtual:cedar-api`
10
- * and resolve `virtual:ud:catch-all` Cedar's aggregate fetch dispatcher
11
- * 2. Installs `node()` from `@universal-deploy/node/vite` to emit a
12
- * self-contained Node server entry at `api/dist/ud/index.js`
9
+ * 1. Installs `cedarUniversalDeployPlugin()` to register per-route API
10
+ * entries (GraphQL, auth, functions) with UD's store.
11
+ * 2. Installs `universalDeploy()` from `@universal-deploy/vite` which
12
+ * provides `catchAll()` (rou3-based route dispatch), `devServer()`, and
13
+ * auto-detection of deployment targets (Node by default, or Netlify/
14
+ * Vercel/Cloudflare if the user has added the corresponding Vite plugin).
13
15
  *
14
16
  * The emitted entry can be launched directly: node api/dist/ud/index.js
15
17
  * That is what `cedar serve api` does.
@@ -1 +1 @@
1
- {"version":3,"file":"buildUDApiServer.d.ts","sourceRoot":"","sources":["../src/buildUDApiServer.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,uBAAuB;IACtC,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAED;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,gBAAgB,GAAU,4BAGpC,uBAA4B,kBA+D9B,CAAA"}
1
+ {"version":3,"file":"buildUDApiServer.d.ts","sourceRoot":"","sources":["../src/buildUDApiServer.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,uBAAuB;IACtC,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,gBAAgB,GAAU,4BAGpC,uBAA4B,kBA6C9B,CAAA"}
@@ -6,23 +6,19 @@ const buildUDApiServer = async ({
6
6
  } = {}) => {
7
7
  const { build } = await import("vite");
8
8
  const { cedarUniversalDeployPlugin } = await import("./plugins/vite-plugin-cedar-universal-deploy.js");
9
- const { node } = await import("@universal-deploy/node/vite");
9
+ const { default: universalDeploy } = await import("@universal-deploy/vite");
10
10
  const rwPaths = getPaths();
11
11
  const outDir = path.join(rwPaths.api.dist, "ud");
12
12
  await build({
13
- // No configFile — we configure everything inline so this build is
14
- // self-contained and does not require a vite.config.ts in api/.
15
- configFile: false,
16
- envFile: false,
17
13
  logLevel: verbose ? "info" : "warn",
18
14
  plugins: [
19
- // Registers virtual:cedar-api with @universal-deploy/store and resolves
20
- // virtual:ud:catch-all → virtual:cedar-api → Cedar's aggregate fetchable.
15
+ // Registers per-route API entries with @universal-deploy/store.
21
16
  cedarUniversalDeployPlugin({ apiRootPath }),
22
- // Emits a self-contained Node server entry (api/dist/ud/index.js) that
23
- // imports virtual:ud:catch-all and starts an srvx HTTP server.
24
- // This is a Vite server-build concern, not Cedar HTML SSR.
25
- ...node()
17
+ // Includes catchAll(), devServer(), and auto-detection of
18
+ // deployment targets. Enables @universal-deploy/node by default
19
+ // when no other target (Netlify, Vercel, Cloudflare) is detected
20
+ // in the user's Vite config.
21
+ universalDeploy()
26
22
  ],
27
23
  // The ssr environment is the Vite mechanism for server-side builds.
28
24
  // Reminder: "ssr" here means "server-side module execution", NOT
@@ -30,21 +26,7 @@ const buildUDApiServer = async ({
30
26
  environments: {
31
27
  ssr: {
32
28
  build: {
33
- outDir,
34
- // Ensure @universal-deploy/node is bundled into the output so the
35
- // emitted entry is self-contained.
36
- rollupOptions: {
37
- output: {
38
- // Produce a single-file entry where possible; srvx chunks are
39
- // split by the node() plugin automatically.
40
- entryFileNames: "[name].js"
41
- }
42
- }
43
- },
44
- resolve: {
45
- // Do not externalise @universal-deploy/node — the node() plugin
46
- // requires it to be bundled into the server entry.
47
- noExternal: ["@universal-deploy/node"]
29
+ outDir
48
30
  }
49
31
  }
50
32
  },