@cedarjs/cli 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.
- package/dist/cfw.js +1 -1
- package/dist/commands/build/buildHandler.js +76 -11
- package/dist/commands/dev/devHandler.js +44 -12
- package/dist/commands/prerenderHandler.js +21 -17
- package/dist/commands/serve.js +216 -21
- package/dist/lib/exec.js +34 -42
- package/dist/lib/locking.js +8 -4
- package/package.json +14 -14
- package/LICENSE +0 -21
package/dist/cfw.js
CHANGED
|
@@ -6,7 +6,7 @@ import execa from "execa";
|
|
|
6
6
|
import { terminalLink } from "termi-link";
|
|
7
7
|
import { getConfigPath } from "@cedarjs/project-config";
|
|
8
8
|
const config = new Configstore("@cedarjs/cli");
|
|
9
|
-
const CFW_PATH = process.env.CFW_PATH ||
|
|
9
|
+
const CFW_PATH = process.env.CFW_PATH || config.get("CFW_PATH");
|
|
10
10
|
if (!CFW_PATH) {
|
|
11
11
|
console.error("Error: You must specify the path to Cedar Framework");
|
|
12
12
|
console.error("Usage: `CFW_PATH=~/gh/cedarjs/cedar yarn cfw <command>");
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
} from "@cedarjs/cli-helpers/packageManager/display";
|
|
12
12
|
import { runBin } from "@cedarjs/cli-helpers/packageManager/exec";
|
|
13
13
|
import {
|
|
14
|
+
buildApi,
|
|
14
15
|
buildApiWithVite,
|
|
15
16
|
cleanApiBuild
|
|
16
17
|
} from "@cedarjs/internal/dist/build/api";
|
|
@@ -20,6 +21,7 @@ import { loadAndValidateSdls } from "@cedarjs/internal/dist/validateSchema";
|
|
|
20
21
|
import { detectPrerenderRoutes } from "@cedarjs/prerender/detection";
|
|
21
22
|
import {} from "@cedarjs/project-config";
|
|
22
23
|
import { timedTelemetry } from "@cedarjs/telemetry";
|
|
24
|
+
import { buildCedarApp } from "@cedarjs/vite/build";
|
|
23
25
|
import { buildUDApiServer } from "@cedarjs/vite/buildUDApiServer";
|
|
24
26
|
import { generatePrismaCommand } from "../../lib/generatePrismaClient.js";
|
|
25
27
|
import { getPaths, getConfig } from "../../lib/index.js";
|
|
@@ -163,25 +165,59 @@ Run ` + c.info(formatCedarCommand(["build"])) + " (without specifying a workspac
|
|
|
163
165
|
title: "Verifying graphql schema...",
|
|
164
166
|
task: loadAndValidateSdls
|
|
165
167
|
},
|
|
166
|
-
//
|
|
167
|
-
//
|
|
168
|
-
//
|
|
169
|
-
|
|
170
|
-
// Step 2 depends on step 1 having completed.
|
|
171
|
-
workspace.includes("api") && {
|
|
168
|
+
// When streaming SSR is enabled, fall back to the legacy separate build
|
|
169
|
+
// paths because streaming SSR has its own complex build orchestration.
|
|
170
|
+
// Phase 7 (SSR/RSC rebuild) will address unifying this path.
|
|
171
|
+
workspace.includes("api") && getConfig().experimental?.streamingSsr?.enabled && {
|
|
172
172
|
title: "Building API...",
|
|
173
173
|
task: async () => {
|
|
174
174
|
await cleanApiBuild();
|
|
175
175
|
await buildApiWithVite();
|
|
176
176
|
}
|
|
177
177
|
},
|
|
178
|
-
|
|
179
|
-
title: "
|
|
178
|
+
workspace.includes("web") && getConfig().experimental?.streamingSsr?.enabled && {
|
|
179
|
+
title: "Building Web...",
|
|
180
180
|
task: async () => {
|
|
181
|
-
|
|
181
|
+
process.env.VITE_CJS_IGNORE_WARNING = "true";
|
|
182
|
+
const createdRequire = createRequire(import.meta.url);
|
|
183
|
+
const buildBinPath = createdRequire.resolve(
|
|
184
|
+
"@cedarjs/vite/bins/cedar-vite-build.mjs"
|
|
185
|
+
);
|
|
186
|
+
await execa(
|
|
187
|
+
`node ${buildBinPath} --webDir="${cedarPaths.web.base}" --verbose=${verbose}`,
|
|
188
|
+
{
|
|
189
|
+
stdio: verbose ? "inherit" : "pipe",
|
|
190
|
+
shell: true,
|
|
191
|
+
cwd: cedarPaths.web.base
|
|
192
|
+
}
|
|
193
|
+
);
|
|
194
|
+
if (!getConfig().experimental?.streamingSsr?.enabled) {
|
|
195
|
+
console.log("Creating 200.html...");
|
|
196
|
+
const indexHtmlPath = path.join(getPaths().web.dist, "index.html");
|
|
197
|
+
fs.copyFileSync(
|
|
198
|
+
indexHtmlPath,
|
|
199
|
+
path.join(getPaths().web.dist, "200.html")
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
},
|
|
204
|
+
// Legacy separate build path (default when not --ud, non-streaming-SSR)
|
|
205
|
+
workspace.includes("api") && !ud && !getConfig().experimental?.streamingSsr?.enabled && {
|
|
206
|
+
title: "Building API...",
|
|
207
|
+
task: async () => {
|
|
208
|
+
await cleanApiBuild();
|
|
209
|
+
const { errors, warnings } = await buildApi();
|
|
210
|
+
if (warnings.length) {
|
|
211
|
+
console.warn(warnings);
|
|
212
|
+
}
|
|
213
|
+
if (errors.length) {
|
|
214
|
+
throw new Error(
|
|
215
|
+
`API build failed with ${errors.length} error(s). See output above for details.`
|
|
216
|
+
);
|
|
217
|
+
}
|
|
182
218
|
}
|
|
183
219
|
},
|
|
184
|
-
workspace.includes("web") && {
|
|
220
|
+
workspace.includes("web") && !ud && !getConfig().experimental?.streamingSsr?.enabled && {
|
|
185
221
|
title: "Building Web...",
|
|
186
222
|
task: async () => {
|
|
187
223
|
process.env.VITE_CJS_IGNORE_WARNING = "true";
|
|
@@ -200,7 +236,30 @@ Run ` + c.info(formatCedarCommand(["build"])) + " (without specifying a workspac
|
|
|
200
236
|
cwd: cedarPaths.web.base
|
|
201
237
|
}
|
|
202
238
|
);
|
|
203
|
-
|
|
239
|
+
console.log("Creating 200.html...");
|
|
240
|
+
const indexHtmlPath = path.join(getPaths().web.dist, "index.html");
|
|
241
|
+
fs.copyFileSync(
|
|
242
|
+
indexHtmlPath,
|
|
243
|
+
path.join(getPaths().web.dist, "200.html")
|
|
244
|
+
);
|
|
245
|
+
}
|
|
246
|
+
},
|
|
247
|
+
// Unified build path (experimental, non-streaming-SSR, --ud)
|
|
248
|
+
(workspace.includes("api") || workspace.includes("web")) && ud && !getConfig().experimental?.streamingSsr?.enabled && {
|
|
249
|
+
title: workspace.includes("api") && workspace.includes("web") ? "Building App..." : workspace.includes("api") ? "Building API..." : "Building Web...",
|
|
250
|
+
task: async () => {
|
|
251
|
+
process.env.VITE_CJS_IGNORE_WARNING = "true";
|
|
252
|
+
if (workspace.includes("api")) {
|
|
253
|
+
await cleanApiBuild();
|
|
254
|
+
}
|
|
255
|
+
const originalCwd = process.cwd();
|
|
256
|
+
process.chdir(cedarPaths.web.base);
|
|
257
|
+
try {
|
|
258
|
+
await buildCedarApp({ verbose, workspace });
|
|
259
|
+
} finally {
|
|
260
|
+
process.chdir(originalCwd);
|
|
261
|
+
}
|
|
262
|
+
if (workspace.includes("web")) {
|
|
204
263
|
console.log("Creating 200.html...");
|
|
205
264
|
const indexHtmlPath = path.join(getPaths().web.dist, "index.html");
|
|
206
265
|
fs.copyFileSync(
|
|
@@ -209,6 +268,12 @@ Run ` + c.info(formatCedarCommand(["build"])) + " (without specifying a workspac
|
|
|
209
268
|
);
|
|
210
269
|
}
|
|
211
270
|
}
|
|
271
|
+
},
|
|
272
|
+
ud && workspace.includes("api") && {
|
|
273
|
+
title: "Bundling API server entry (Universal Deploy)...",
|
|
274
|
+
task: async () => {
|
|
275
|
+
await buildUDApiServer({ verbose });
|
|
276
|
+
}
|
|
212
277
|
}
|
|
213
278
|
].filter((t) => Boolean(t));
|
|
214
279
|
const triggerPrerender = async () => {
|
|
@@ -68,19 +68,40 @@ const handler = async ({
|
|
|
68
68
|
}
|
|
69
69
|
webPortChangeNeeded = webAvailablePort !== webPreferredPort;
|
|
70
70
|
}
|
|
71
|
-
if (
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
71
|
+
if (ud) {
|
|
72
|
+
if (webPortChangeNeeded) {
|
|
73
|
+
const message = [
|
|
74
|
+
"The currently configured port for the development server is",
|
|
75
|
+
"unavailable. Suggested change to your port, which can be changed in",
|
|
76
|
+
"cedar.toml (or redwood.toml):\n",
|
|
77
|
+
` - Web to use port ${webAvailablePort} instead`,
|
|
78
|
+
"of your currently configured",
|
|
79
|
+
`${webPreferredPort}
|
|
79
80
|
`,
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
81
|
+
"\nCannot run the development server until your configured port is",
|
|
82
|
+
"changed or becomes available."
|
|
83
|
+
].filter(Boolean).join(" ");
|
|
84
|
+
exitWithError(void 0, { message });
|
|
85
|
+
}
|
|
86
|
+
} else {
|
|
87
|
+
if (apiPortChangeNeeded || webPortChangeNeeded) {
|
|
88
|
+
const message = [
|
|
89
|
+
"The currently configured ports for the development server are",
|
|
90
|
+
"unavailable. Suggested changes to your ports, which can be changed in",
|
|
91
|
+
"cedar.toml (or redwood.toml), are:\n",
|
|
92
|
+
apiPortChangeNeeded && ` - API to use port ${apiAvailablePort} instead`,
|
|
93
|
+
apiPortChangeNeeded && "of your currently configured",
|
|
94
|
+
apiPortChangeNeeded && `${apiPreferredPort}
|
|
95
|
+
`,
|
|
96
|
+
webPortChangeNeeded && ` - Web to use port ${webAvailablePort} instead`,
|
|
97
|
+
webPortChangeNeeded && "of your currently configured",
|
|
98
|
+
webPortChangeNeeded && `${webPreferredPort}
|
|
99
|
+
`,
|
|
100
|
+
"\nCannot run the development server until your configured ports are",
|
|
101
|
+
"changed or become available."
|
|
102
|
+
].filter(Boolean).join(" ");
|
|
103
|
+
exitWithError(void 0, { message });
|
|
104
|
+
}
|
|
84
105
|
}
|
|
85
106
|
if (workspace.includes("api")) {
|
|
86
107
|
try {
|
|
@@ -90,6 +111,17 @@ const handler = async ({
|
|
|
90
111
|
errorTelemetry(process.argv, `Error generating prisma client: ${message}`);
|
|
91
112
|
console.error(c.error(message));
|
|
92
113
|
}
|
|
114
|
+
if (!ud && !serverFile) {
|
|
115
|
+
try {
|
|
116
|
+
await shutdownPort(apiAvailablePort);
|
|
117
|
+
} catch (e) {
|
|
118
|
+
const message = getErrorMessage(e);
|
|
119
|
+
errorTelemetry(process.argv, `Error shutting down "api": ${message}`);
|
|
120
|
+
console.error(
|
|
121
|
+
`Error whilst shutting down "api" port: ${c.error(message)}`
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
93
125
|
}
|
|
94
126
|
if (workspace.includes("web") && webAvailablePort !== void 0) {
|
|
95
127
|
try {
|
|
@@ -151,24 +151,28 @@ const getTasks = async (dryrun, routerPathFilter = null) => {
|
|
|
151
151
|
}
|
|
152
152
|
];
|
|
153
153
|
}
|
|
154
|
-
return routesToPrerender.flatMap(
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
const outputHtmlPath = mapRouterPathToHtml(routeToPrerender.path);
|
|
159
|
-
return {
|
|
160
|
-
title: `Prerendering ${routeToPrerender.path} -> ${outputHtmlPath}`,
|
|
161
|
-
task: async () => {
|
|
162
|
-
await prerenderRoute(
|
|
163
|
-
prerenderer,
|
|
164
|
-
queryCache,
|
|
165
|
-
routeToPrerender,
|
|
166
|
-
dryrun,
|
|
167
|
-
outputHtmlPath
|
|
168
|
-
);
|
|
154
|
+
return routesToPrerender.flatMap(
|
|
155
|
+
(routeToPrerender) => {
|
|
156
|
+
if (routerPathFilter && routeToPrerender.path !== routerPathFilter) {
|
|
157
|
+
return [];
|
|
169
158
|
}
|
|
170
|
-
|
|
171
|
-
|
|
159
|
+
const outputHtmlPath = mapRouterPathToHtml(routeToPrerender.path);
|
|
160
|
+
return [
|
|
161
|
+
{
|
|
162
|
+
title: `Prerendering ${routeToPrerender.path} -> ${outputHtmlPath}`,
|
|
163
|
+
task: async () => {
|
|
164
|
+
await prerenderRoute(
|
|
165
|
+
prerenderer,
|
|
166
|
+
queryCache,
|
|
167
|
+
routeToPrerender,
|
|
168
|
+
dryrun,
|
|
169
|
+
outputHtmlPath
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
];
|
|
174
|
+
}
|
|
175
|
+
);
|
|
172
176
|
});
|
|
173
177
|
return listrTasks;
|
|
174
178
|
};
|
package/dist/commands/serve.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { fork } from "node:child_process";
|
|
2
2
|
import fs from "node:fs";
|
|
3
|
+
import net from "node:net";
|
|
3
4
|
import path from "node:path";
|
|
4
5
|
import { terminalLink } from "termi-link";
|
|
5
6
|
import * as apiServerCLIConfig from "@cedarjs/api-server/apiCliConfig";
|
|
@@ -18,7 +19,14 @@ const builder = async (yargs) => {
|
|
|
18
19
|
yargs.command({
|
|
19
20
|
command: "$0",
|
|
20
21
|
description: bothServerCLIConfig.description,
|
|
21
|
-
builder:
|
|
22
|
+
builder: (yargs2) => {
|
|
23
|
+
bothServerCLIConfig.builder(yargs2);
|
|
24
|
+
return yargs2.option("ud", {
|
|
25
|
+
description: "Use the Universal Deploy server for the API side. The web side is served by the existing static file server. Pass --ud to opt in; the default is Fastify for both sides.",
|
|
26
|
+
type: "boolean",
|
|
27
|
+
default: false
|
|
28
|
+
});
|
|
29
|
+
},
|
|
22
30
|
handler: async (argv) => {
|
|
23
31
|
recordTelemetryAttributes({
|
|
24
32
|
command: "serve",
|
|
@@ -26,6 +34,110 @@ const builder = async (yargs) => {
|
|
|
26
34
|
host: argv.host,
|
|
27
35
|
socket: argv.socket
|
|
28
36
|
});
|
|
37
|
+
if (argv.ud) {
|
|
38
|
+
if (argv.port) {
|
|
39
|
+
console.error(
|
|
40
|
+
c.error(
|
|
41
|
+
"\n The --port flag is not supported with --ud. Use --web-port and --api-port instead.\n"
|
|
42
|
+
)
|
|
43
|
+
);
|
|
44
|
+
process.exit(1);
|
|
45
|
+
}
|
|
46
|
+
const udEntryPath = path.join(getPaths().api.dist, "ud", "index.js");
|
|
47
|
+
if (!fs.existsSync(udEntryPath)) {
|
|
48
|
+
console.error(
|
|
49
|
+
c.error(
|
|
50
|
+
`
|
|
51
|
+
Universal Deploy server entry not found at ${udEntryPath}.
|
|
52
|
+
Please run \`yarn cedar build --ud\` before serving.
|
|
53
|
+
`
|
|
54
|
+
)
|
|
55
|
+
);
|
|
56
|
+
process.exit(1);
|
|
57
|
+
}
|
|
58
|
+
const webDistIndexHtml = path.join(getPaths().web.dist, "index.html");
|
|
59
|
+
if (!fs.existsSync(webDistIndexHtml)) {
|
|
60
|
+
console.error(
|
|
61
|
+
c.error(
|
|
62
|
+
"\n Web build artifacts not found.\n Please run `yarn cedar build` before serving.\n"
|
|
63
|
+
)
|
|
64
|
+
);
|
|
65
|
+
process.exit(1);
|
|
66
|
+
}
|
|
67
|
+
if (serverFileExists()) {
|
|
68
|
+
console.warn(
|
|
69
|
+
c.warning(
|
|
70
|
+
"\n Note: api/src/server.ts was detected. This file is a Fastify concept and will be ignored when using --ud. You are testing the experimental UD support, so the behavior will not match your production Fastify setup.\n"
|
|
71
|
+
)
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
const { getAPIHost, getAPIPort, getWebHost, getWebPort } = await import("@cedarjs/api-server/cliHelpers");
|
|
75
|
+
const apiPort = argv.apiPort ?? getAPIPort();
|
|
76
|
+
const apiHost = argv.apiHost ?? getAPIHost();
|
|
77
|
+
const webPort = argv.webPort ?? getWebPort();
|
|
78
|
+
const webHost = argv.webHost ?? getWebHost();
|
|
79
|
+
const apiRootPath = argv.apiRootPath ?? "/";
|
|
80
|
+
const apiProxyTarget = [
|
|
81
|
+
"http://",
|
|
82
|
+
apiHost.includes(":") ? `[${apiHost}]` : apiHost,
|
|
83
|
+
":",
|
|
84
|
+
apiPort,
|
|
85
|
+
apiRootPath
|
|
86
|
+
].join("");
|
|
87
|
+
const { redwoodFastifyWeb } = await import("@cedarjs/fastify-web");
|
|
88
|
+
const { createFastifyInstance } = await import("@cedarjs/api-server/fastify");
|
|
89
|
+
const webFastify = await createFastifyInstance();
|
|
90
|
+
webFastify.register(redwoodFastifyWeb, {
|
|
91
|
+
redwood: {
|
|
92
|
+
apiProxyTarget
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
await webFastify.listen({
|
|
96
|
+
port: webPort,
|
|
97
|
+
host: webHost
|
|
98
|
+
});
|
|
99
|
+
const child = fork(
|
|
100
|
+
udEntryPath,
|
|
101
|
+
["--port", String(apiPort), "--host", apiHost],
|
|
102
|
+
{
|
|
103
|
+
execArgv: process.execArgv,
|
|
104
|
+
env: {
|
|
105
|
+
...process.env,
|
|
106
|
+
NODE_ENV: process.env.NODE_ENV ?? "production",
|
|
107
|
+
PORT: String(apiPort),
|
|
108
|
+
HOST: apiHost
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
);
|
|
112
|
+
child.on("error", (err) => {
|
|
113
|
+
console.error(
|
|
114
|
+
c.error(`
|
|
115
|
+
Failed to start UD API server: ${err.message}
|
|
116
|
+
`)
|
|
117
|
+
);
|
|
118
|
+
process.exit(1);
|
|
119
|
+
});
|
|
120
|
+
child.on("exit", (code) => {
|
|
121
|
+
if (code !== 0) {
|
|
122
|
+
console.error(
|
|
123
|
+
c.error(`
|
|
124
|
+
UD API server exited with code ${code}
|
|
125
|
+
`)
|
|
126
|
+
);
|
|
127
|
+
process.exit(1);
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
console.log(`Web server listening at http://${webHost}:${webPort}`);
|
|
131
|
+
process.stdout.write(
|
|
132
|
+
`API server starting at http://${apiHost}:${apiPort}...`
|
|
133
|
+
);
|
|
134
|
+
await waitForPort(apiHost, apiPort);
|
|
135
|
+
process.stdout.write(
|
|
136
|
+
`\rAPI server listening at http://${apiHost}:${apiPort}
|
|
137
|
+
`
|
|
138
|
+
);
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
29
141
|
if (serverFileExists()) {
|
|
30
142
|
const serveBothHandlers = await import("./serveBothHandler.js");
|
|
31
143
|
await serveBothHandlers.bothServerFileHandler(argv);
|
|
@@ -51,7 +163,7 @@ const builder = async (yargs) => {
|
|
|
51
163
|
return yargs2.option("ud", {
|
|
52
164
|
// UD serving is opt-in. Pass --ud to use the new srvx server instead
|
|
53
165
|
// of the legacy Fastify server.
|
|
54
|
-
description: "Use the Universal Deploy server
|
|
166
|
+
description: "Use the Universal Deploy server. Pass --ud to opt in; the default is Fastify.",
|
|
55
167
|
type: "boolean",
|
|
56
168
|
default: false
|
|
57
169
|
});
|
|
@@ -71,7 +183,7 @@ const builder = async (yargs) => {
|
|
|
71
183
|
c.error(
|
|
72
184
|
`
|
|
73
185
|
Universal Deploy server entry not found at ${udEntryPath}.
|
|
74
|
-
Please run \`yarn cedar build
|
|
186
|
+
Please run \`yarn cedar build --ud\` before serving.
|
|
75
187
|
`
|
|
76
188
|
)
|
|
77
189
|
);
|
|
@@ -84,17 +196,34 @@ const builder = async (yargs) => {
|
|
|
84
196
|
if (argv.host) {
|
|
85
197
|
udArgs.push("--host", argv.host);
|
|
86
198
|
}
|
|
199
|
+
const child = fork(udEntryPath, udArgs, {
|
|
200
|
+
execArgv: process.execArgv,
|
|
201
|
+
env: {
|
|
202
|
+
...process.env,
|
|
203
|
+
NODE_ENV: process.env.NODE_ENV ?? "production",
|
|
204
|
+
PORT: argv.port ? String(argv.port) : process.env.PORT,
|
|
205
|
+
HOST: argv.host ?? process.env.HOST
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
child.on("error", (err) => {
|
|
209
|
+
console.error(
|
|
210
|
+
c.error(`
|
|
211
|
+
Failed to start UD server: ${err.message}
|
|
212
|
+
`)
|
|
213
|
+
);
|
|
214
|
+
process.exit(1);
|
|
215
|
+
});
|
|
216
|
+
const apiPort = argv.port ?? parseInt(process.env.PORT ?? "8911", 10);
|
|
217
|
+
const apiHost = argv.host ?? process.env.HOST ?? "localhost";
|
|
218
|
+
process.stdout.write(
|
|
219
|
+
`API server starting at http://${apiHost}:${apiPort}...`
|
|
220
|
+
);
|
|
221
|
+
await waitForPort(apiHost, apiPort);
|
|
222
|
+
process.stdout.write(
|
|
223
|
+
`\rAPI server listening at http://${apiHost}:${apiPort}
|
|
224
|
+
`
|
|
225
|
+
);
|
|
87
226
|
await new Promise((resolve, reject) => {
|
|
88
|
-
const child = fork(udEntryPath, udArgs, {
|
|
89
|
-
execArgv: process.execArgv,
|
|
90
|
-
env: {
|
|
91
|
-
...process.env,
|
|
92
|
-
NODE_ENV: process.env.NODE_ENV ?? "production",
|
|
93
|
-
PORT: argv.port ? String(argv.port) : process.env.PORT,
|
|
94
|
-
HOST: argv.host ?? process.env.HOST
|
|
95
|
-
}
|
|
96
|
-
});
|
|
97
|
-
child.on("error", reject);
|
|
98
227
|
child.on("exit", (code) => {
|
|
99
228
|
if (code !== 0) {
|
|
100
229
|
reject(new Error(`UD server exited with code ${code}`));
|
|
@@ -166,6 +295,20 @@ const builder = async (yargs) => {
|
|
|
166
295
|
);
|
|
167
296
|
process.exit(1);
|
|
168
297
|
}
|
|
298
|
+
if (argv.ud) {
|
|
299
|
+
const udEntryPath = path.join(getPaths().api.dist, "ud", "index.js");
|
|
300
|
+
if (!fs.existsSync(udEntryPath)) {
|
|
301
|
+
console.error(
|
|
302
|
+
c.error(
|
|
303
|
+
`
|
|
304
|
+
Universal Deploy server entry not found at ${udEntryPath}.
|
|
305
|
+
Please run \`yarn cedar build --ud\` before serving.
|
|
306
|
+
`
|
|
307
|
+
)
|
|
308
|
+
);
|
|
309
|
+
process.exit(1);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
169
312
|
}
|
|
170
313
|
if (positionalArgs.length === 1) {
|
|
171
314
|
if (!apiSideExists && !rscEnabled) {
|
|
@@ -176,14 +319,38 @@ const builder = async (yargs) => {
|
|
|
176
319
|
);
|
|
177
320
|
process.exit(1);
|
|
178
321
|
}
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
322
|
+
if (argv.ud) {
|
|
323
|
+
const udEntryPath = path.join(getPaths().api.dist, "ud", "index.js");
|
|
324
|
+
if (!fs.existsSync(udEntryPath)) {
|
|
325
|
+
console.error(
|
|
326
|
+
c.error(
|
|
327
|
+
`
|
|
328
|
+
Universal Deploy server entry not found at ${udEntryPath}.
|
|
329
|
+
Please run \`yarn cedar build --ud\` before serving.
|
|
330
|
+
`
|
|
331
|
+
)
|
|
332
|
+
);
|
|
333
|
+
process.exit(1);
|
|
334
|
+
}
|
|
335
|
+
const webDistIndexHtml = path.join(getPaths().web.dist, "index.html");
|
|
336
|
+
if (!fs.existsSync(webDistIndexHtml)) {
|
|
337
|
+
console.error(
|
|
338
|
+
c.error(
|
|
339
|
+
"\n Web build artifacts not found.\n Please run `yarn cedar build` before serving.\n"
|
|
340
|
+
)
|
|
341
|
+
);
|
|
342
|
+
process.exit(1);
|
|
343
|
+
}
|
|
344
|
+
} else {
|
|
345
|
+
const apiExistsButIsNotBuilt = apiSideExists && !fs.existsSync(getPaths().api.dist);
|
|
346
|
+
if (apiExistsButIsNotBuilt || !webSideIsBuilt(streamingEnabled || rscEnabled)) {
|
|
347
|
+
console.error(
|
|
348
|
+
c.error(
|
|
349
|
+
"\nPlease run `yarn cedar build` before trying to serve your Cedar app.\n"
|
|
350
|
+
)
|
|
351
|
+
);
|
|
352
|
+
process.exit(1);
|
|
353
|
+
}
|
|
187
354
|
}
|
|
188
355
|
}
|
|
189
356
|
if (!process.env.NODE_ENV) {
|
|
@@ -205,6 +372,34 @@ function webSideIsBuilt(isStreamingOrRSC) {
|
|
|
205
372
|
return fs.existsSync(path.join(getPaths().web.dist, "index.html"));
|
|
206
373
|
}
|
|
207
374
|
}
|
|
375
|
+
function waitForPort(host, port) {
|
|
376
|
+
const maxAttempts = 50;
|
|
377
|
+
const intervalMs = 200;
|
|
378
|
+
return new Promise((resolve, reject) => {
|
|
379
|
+
let attempts = 0;
|
|
380
|
+
const tryConnect = () => {
|
|
381
|
+
attempts++;
|
|
382
|
+
const socket = net.createConnection({ host, port });
|
|
383
|
+
socket.on("connect", () => {
|
|
384
|
+
socket.destroy();
|
|
385
|
+
resolve();
|
|
386
|
+
});
|
|
387
|
+
socket.on("error", () => {
|
|
388
|
+
socket.destroy();
|
|
389
|
+
if (attempts >= maxAttempts) {
|
|
390
|
+
reject(
|
|
391
|
+
new Error(
|
|
392
|
+
`API server did not become ready on port ${port} after ${maxAttempts * intervalMs}ms`
|
|
393
|
+
)
|
|
394
|
+
);
|
|
395
|
+
} else {
|
|
396
|
+
setTimeout(tryConnect, intervalMs);
|
|
397
|
+
}
|
|
398
|
+
});
|
|
399
|
+
};
|
|
400
|
+
tryConnect();
|
|
401
|
+
});
|
|
402
|
+
}
|
|
208
403
|
export {
|
|
209
404
|
builder,
|
|
210
405
|
command,
|
package/dist/lib/exec.js
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
1
2
|
import path from "node:path";
|
|
2
|
-
import { createServer,
|
|
3
|
-
import { ViteNodeRunner } from "vite-node/client";
|
|
4
|
-
import { ViteNodeServer } from "vite-node/server";
|
|
5
|
-
import { installSourcemapsSupport } from "vite-node/source-map";
|
|
3
|
+
import { createServer, isRunnableDevEnvironment } from "vite";
|
|
6
4
|
import { getPaths, importStatementPath } from "@cedarjs/project-config";
|
|
7
5
|
import {
|
|
8
6
|
cedarCellTransform,
|
|
@@ -10,8 +8,21 @@ import {
|
|
|
10
8
|
cedarjsJobPathInjectorPlugin,
|
|
11
9
|
cedarSwapApolloProvider,
|
|
12
10
|
cedarImportDirPlugin,
|
|
13
|
-
cedarAutoImportsPlugin
|
|
11
|
+
cedarAutoImportsPlugin,
|
|
12
|
+
cedarCjsCompatPlugin
|
|
14
13
|
} from "@cedarjs/vite";
|
|
14
|
+
function resolveExtension(id) {
|
|
15
|
+
if (existsSync(id)) {
|
|
16
|
+
return id;
|
|
17
|
+
}
|
|
18
|
+
const withoutExt = /\.jsx?$/.test(id) ? id.replace(/\.jsx?$/, "") : id;
|
|
19
|
+
for (const ext of [".ts", ".tsx", ".js", ".jsx"]) {
|
|
20
|
+
if (existsSync(withoutExt + ext)) {
|
|
21
|
+
return withoutExt + ext;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return id;
|
|
25
|
+
}
|
|
15
26
|
async function runScriptFunction({
|
|
16
27
|
path: scriptPath,
|
|
17
28
|
functionName,
|
|
@@ -22,10 +33,16 @@ async function runScriptFunction({
|
|
|
22
33
|
const server = await createServer({
|
|
23
34
|
mode: "production",
|
|
24
35
|
optimizeDeps: {
|
|
25
|
-
// This is recommended in the vite-node readme
|
|
26
36
|
noDiscovery: true,
|
|
27
37
|
include: void 0
|
|
28
38
|
},
|
|
39
|
+
server: {
|
|
40
|
+
hmr: false,
|
|
41
|
+
watch: null
|
|
42
|
+
},
|
|
43
|
+
environments: {
|
|
44
|
+
nodeRunnerEnv: {}
|
|
45
|
+
},
|
|
29
46
|
resolve: {
|
|
30
47
|
alias: [
|
|
31
48
|
{
|
|
@@ -52,18 +69,12 @@ async function runScriptFunction({
|
|
|
52
69
|
const webImportBase = importStatementPath(getPaths().web.base);
|
|
53
70
|
if (importer.startsWith(apiImportBase)) {
|
|
54
71
|
const apiImportSrc = importStatementPath(getPaths().api.src);
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
resolvedId = resolvedId.replace(/\.jsx?$/, "");
|
|
58
|
-
}
|
|
59
|
-
return { id: resolvedId };
|
|
72
|
+
const resolvedId = id.replace("src", apiImportSrc);
|
|
73
|
+
return { id: resolveExtension(resolvedId) };
|
|
60
74
|
} else if (importer.startsWith(webImportBase)) {
|
|
61
75
|
const webImportSrc = importStatementPath(getPaths().web.src);
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
resolvedId = resolvedId.replace(/\.jsx?$/, "");
|
|
65
|
-
}
|
|
66
|
-
return { id: resolvedId };
|
|
76
|
+
const resolvedId = id.replace("src", webImportSrc);
|
|
77
|
+
return { id: resolveExtension(resolvedId) };
|
|
67
78
|
}
|
|
68
79
|
return null;
|
|
69
80
|
}
|
|
@@ -71,6 +82,7 @@ async function runScriptFunction({
|
|
|
71
82
|
]
|
|
72
83
|
},
|
|
73
84
|
plugins: [
|
|
85
|
+
cedarCjsCompatPlugin(),
|
|
74
86
|
cedarjsResolveCedarStyleImportsPlugin(),
|
|
75
87
|
cedarCellTransform(),
|
|
76
88
|
cedarjsJobPathInjectorPlugin(),
|
|
@@ -79,41 +91,21 @@ async function runScriptFunction({
|
|
|
79
91
|
cedarAutoImportsPlugin()
|
|
80
92
|
]
|
|
81
93
|
});
|
|
82
|
-
|
|
83
|
-
|
|
94
|
+
const env = server.environments.nodeRunnerEnv;
|
|
95
|
+
if (!env || !isRunnableDevEnvironment(env)) {
|
|
96
|
+
await server.close();
|
|
97
|
+
throw new Error("Vite environment is not runnable.");
|
|
84
98
|
}
|
|
85
|
-
const node = new ViteNodeServer(server, {
|
|
86
|
-
transformMode: {
|
|
87
|
-
ssr: [/.*/],
|
|
88
|
-
web: [/\/web\//]
|
|
89
|
-
},
|
|
90
|
-
deps: {
|
|
91
|
-
fallbackCJS: true
|
|
92
|
-
}
|
|
93
|
-
});
|
|
94
|
-
installSourcemapsSupport({
|
|
95
|
-
getSourceMap: (source) => node.getSourceMap(source)
|
|
96
|
-
});
|
|
97
|
-
const runner = new ViteNodeRunner({
|
|
98
|
-
root: server.config.root,
|
|
99
|
-
base: server.config.base,
|
|
100
|
-
fetchModule(id) {
|
|
101
|
-
return node.fetchModule(id);
|
|
102
|
-
},
|
|
103
|
-
resolveId(id, importer) {
|
|
104
|
-
return node.resolveId(id, importer);
|
|
105
|
-
}
|
|
106
|
-
});
|
|
107
99
|
let returnValue;
|
|
108
100
|
let scriptError = null;
|
|
109
101
|
try {
|
|
110
|
-
const script = await runner.
|
|
102
|
+
const script = await env.runner.import(scriptPath);
|
|
111
103
|
returnValue = await script[functionName](args);
|
|
112
104
|
} catch (error) {
|
|
113
105
|
scriptError = error;
|
|
114
106
|
}
|
|
115
107
|
try {
|
|
116
|
-
const { db } = await runner.
|
|
108
|
+
const { db } = await env.runner.import(path.join(getPaths().api.lib, "db"));
|
|
117
109
|
db.$disconnect();
|
|
118
110
|
} catch (e) {
|
|
119
111
|
}
|
package/dist/lib/locking.js
CHANGED
|
@@ -32,11 +32,15 @@ function unsetLock(identifier) {
|
|
|
32
32
|
}
|
|
33
33
|
function isLockSet(identifier) {
|
|
34
34
|
const lockfilePath = path.join(getPaths().generated.base, "locks", identifier);
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
35
|
+
let createdAt;
|
|
36
|
+
try {
|
|
37
|
+
createdAt = fs.statSync(lockfilePath).birthtimeMs;
|
|
38
|
+
} catch (error) {
|
|
39
|
+
if (isErrorWithCode(error, "ENOENT")) {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
throw error;
|
|
38
43
|
}
|
|
39
|
-
const createdAt = fs.statSync(lockfilePath).birthtimeMs;
|
|
40
44
|
if (Date.now() - createdAt > 36e5) {
|
|
41
45
|
unsetLock(identifier);
|
|
42
46
|
return false;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cedarjs/cli",
|
|
3
|
-
"version": "4.1.1-next.
|
|
3
|
+
"version": "4.1.1-next.55",
|
|
4
4
|
"description": "The CedarJS Command Line",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -31,18 +31,19 @@
|
|
|
31
31
|
"test:watch": "vitest watch"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@babel/parser": "7.29.
|
|
34
|
+
"@babel/parser": "7.29.3",
|
|
35
35
|
"@babel/preset-typescript": "7.28.5",
|
|
36
|
-
"@cedarjs/api-server": "4.1.
|
|
37
|
-
"@cedarjs/cli-helpers": "4.1.
|
|
38
|
-
"@cedarjs/fastify-web": "4.1.
|
|
39
|
-
"@cedarjs/internal": "4.1.
|
|
40
|
-
"@cedarjs/prerender": "4.1.
|
|
41
|
-
"@cedarjs/project-config": "4.1.
|
|
42
|
-
"@cedarjs/structure": "4.1.
|
|
43
|
-
"@cedarjs/telemetry": "4.1.
|
|
44
|
-
"@cedarjs/utils": "4.1.
|
|
45
|
-
"@cedarjs/
|
|
36
|
+
"@cedarjs/api-server": "4.1.0",
|
|
37
|
+
"@cedarjs/cli-helpers": "4.1.0",
|
|
38
|
+
"@cedarjs/fastify-web": "4.1.0",
|
|
39
|
+
"@cedarjs/internal": "4.1.0",
|
|
40
|
+
"@cedarjs/prerender": "4.1.0",
|
|
41
|
+
"@cedarjs/project-config": "4.1.0",
|
|
42
|
+
"@cedarjs/structure": "4.1.0",
|
|
43
|
+
"@cedarjs/telemetry": "4.1.0",
|
|
44
|
+
"@cedarjs/utils": "4.1.0",
|
|
45
|
+
"@cedarjs/vite": "4.1.0",
|
|
46
|
+
"@cedarjs/web-server": "4.1.0",
|
|
46
47
|
"@listr2/prompt-adapter-enquirer": "4.2.1",
|
|
47
48
|
"@opentelemetry/api": "1.9.0",
|
|
48
49
|
"@opentelemetry/core": "1.30.1",
|
|
@@ -88,7 +89,6 @@
|
|
|
88
89
|
"title-case": "3.0.3",
|
|
89
90
|
"unionfs": "4.6.0",
|
|
90
91
|
"uuid": "11.1.0",
|
|
91
|
-
"vite-node": "3.2.4",
|
|
92
92
|
"yargs": "17.7.2"
|
|
93
93
|
},
|
|
94
94
|
"devDependencies": {
|
|
@@ -108,5 +108,5 @@
|
|
|
108
108
|
"publishConfig": {
|
|
109
109
|
"access": "public"
|
|
110
110
|
},
|
|
111
|
-
"gitHead": "
|
|
111
|
+
"gitHead": "3905ed045508b861b495f8d5630d76c7a157d8f1"
|
|
112
112
|
}
|
package/LICENSE
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2025 Cedar
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|