@cedarjs/cli 5.0.0-canary.2341 → 5.0.0-canary.2347

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.
@@ -28,7 +28,7 @@ const builder = (yargs) => {
28
28
  }).option("ud", {
29
29
  type: "boolean",
30
30
  default: false,
31
- description: "Build the Universal Deploy server entry (api/dist/ud/index.js)."
31
+ description: "Build the Universal Deploy server entry (api/dist/ud/)."
32
32
  }).middleware(() => {
33
33
  const check = checkNodeVersion();
34
34
  if (check.ok) {
@@ -1,7 +1,11 @@
1
1
  import fs from "node:fs";
2
2
  import path from "node:path";
3
3
  import { Listr } from "listr2";
4
- import { addApiPackages, colors as c } from "@cedarjs/cli-helpers";
4
+ import {
5
+ addApiPackages,
6
+ addWebPackages,
7
+ colors as c
8
+ } from "@cedarjs/cli-helpers";
5
9
  import {
6
10
  getConfigPath,
7
11
  getMigrationsPath,
@@ -14,6 +18,10 @@ function getApiPackageJson() {
14
18
  const apiPackageJsonPath = path.join(getPaths().api.base, "package.json");
15
19
  return JSON.parse(fs.readFileSync(apiPackageJsonPath, "utf-8"));
16
20
  }
21
+ function getWebPackageJson() {
22
+ const webPackageJsonPath = path.join(getPaths().web.base, "package.json");
23
+ return JSON.parse(fs.readFileSync(webPackageJsonPath, "utf-8"));
24
+ }
17
25
  function hasPackage(packageJson, packageName) {
18
26
  return Boolean(
19
27
  packageJson.dependencies?.[packageName] || packageJson.devDependencies?.[packageName]
@@ -147,12 +155,88 @@ function addLiveQueryListenerToGraphqlHandler({ force }) {
147
155
  skipped: false
148
156
  };
149
157
  }
158
+ function addConfigureGqlormToApp({ force }) {
159
+ const appPath = getPaths().web.app;
160
+ if (!fs.existsSync(appPath)) {
161
+ return {
162
+ skipped: true,
163
+ reason: `${path.basename(appPath)} not found`
164
+ };
165
+ }
166
+ const content = fs.readFileSync(appPath, "utf-8");
167
+ const contentLines = content.split("\n");
168
+ const hasGqlormImport = contentLines.some(
169
+ (line) => line.includes("from '@cedarjs/gqlorm/setup'")
170
+ );
171
+ const hasSchemaImport = contentLines.some(
172
+ (line) => line.includes("from '../../.cedar/gqlorm-schema.json'")
173
+ );
174
+ const hasConfigureCall = contentLines.some(
175
+ (line) => line.includes("configureGqlorm({ schema })")
176
+ );
177
+ if (hasGqlormImport && hasSchemaImport && hasConfigureCall && !force) {
178
+ return {
179
+ skipped: true,
180
+ reason: "configureGqlorm is already wired into App"
181
+ };
182
+ }
183
+ if (!hasGqlormImport) {
184
+ const redwoodWebImportIndex = contentLines.findIndex(
185
+ (line) => line.includes("from '@cedarjs/web'")
186
+ );
187
+ if (redwoodWebImportIndex === -1) {
188
+ return {
189
+ skipped: true,
190
+ reason: "Unexpected syntax. Could not find @cedarjs/web import to insert gqlorm import"
191
+ };
192
+ }
193
+ contentLines.splice(
194
+ redwoodWebImportIndex,
195
+ 0,
196
+ "import { configureGqlorm } from '@cedarjs/gqlorm/setup'"
197
+ );
198
+ }
199
+ if (!hasSchemaImport) {
200
+ const fatalErrorPageIndex = contentLines.findIndex(
201
+ (line) => line.includes("import FatalErrorPage from 'src/pages/FatalErrorPage'")
202
+ );
203
+ if (fatalErrorPageIndex === -1) {
204
+ return {
205
+ skipped: true,
206
+ reason: "Unexpected syntax. Could not find FatalErrorPage import to insert schema import"
207
+ };
208
+ }
209
+ contentLines.splice(
210
+ fatalErrorPageIndex + 1,
211
+ 0,
212
+ "import schema from '../../.cedar/gqlorm-schema.json' with { type: 'json' }"
213
+ );
214
+ }
215
+ if (!hasConfigureCall) {
216
+ const appComponentIndex = contentLines.findIndex(
217
+ (line) => /^const App\s*=/.test(line)
218
+ );
219
+ if (appComponentIndex === -1) {
220
+ return {
221
+ skipped: true,
222
+ reason: "Unexpected syntax. Could not find `const App =` to insert configureGqlorm call"
223
+ };
224
+ }
225
+ contentLines.splice(appComponentIndex, 0, "configureGqlorm({ schema })", "");
226
+ }
227
+ fs.writeFileSync(appPath, contentLines.join("\n"));
228
+ return {
229
+ skipped: false
230
+ };
231
+ }
150
232
  async function handler({ force, verbose }) {
151
233
  const projectIsTypescript = isTypeScriptProject();
152
234
  const apiPackageJson = getApiPackageJson();
153
235
  const migrationsPath = await getMigrationsPath(getPaths().api.prismaConfig);
154
236
  const hasRealtimeDependency = hasPackage(apiPackageJson, "@cedarjs/realtime");
155
237
  const hasPgDependency = hasPackage(apiPackageJson, "pg");
238
+ const webPackageJson = getWebPackageJson();
239
+ const hasGqlormDependency = hasPackage(webPackageJson, "@cedarjs/gqlorm");
156
240
  const ext = projectIsTypescript ? "ts" : "js";
157
241
  const migrationTemplatePath = path.resolve(
158
242
  import.meta.dirname,
@@ -244,7 +328,7 @@ async function handler({ force, verbose }) {
244
328
  },
245
329
  {
246
330
  ...addApiPackages(["pg@^8.18.0"]),
247
- title: "Adding pg dependency to your api side...",
331
+ title: "Adding pg dependency to your api workspace...",
248
332
  skip: () => {
249
333
  if (hasPgDependency) {
250
334
  return "pg is already installed";
@@ -297,6 +381,25 @@ async function handler({ force, verbose }) {
297
381
  }
298
382
  }
299
383
  },
384
+ {
385
+ ...addWebPackages(["@cedarjs/gqlorm"]),
386
+ title: "Adding @cedarjs/gqlorm to your web workspace...",
387
+ skip: () => {
388
+ if (hasGqlormDependency) {
389
+ return "@cedarjs/gqlorm is already installed";
390
+ }
391
+ return false;
392
+ }
393
+ },
394
+ {
395
+ title: "Wiring configureGqlorm into App.tsx...",
396
+ task: (_ctx, task) => {
397
+ const result = addConfigureGqlormToApp({ force });
398
+ if (result.skipped) {
399
+ task.skip(result.reason);
400
+ }
401
+ }
402
+ },
300
403
  {
301
404
  title: "One more thing...",
302
405
  task: (_ctx, task) => {
@@ -1,7 +1,7 @@
1
- import { fork } from "node:child_process";
2
1
  import fs from "node:fs";
3
- import net from "node:net";
4
2
  import path from "node:path";
3
+ import { pathToFileURL } from "node:url";
4
+ import { serve as serveSrvx } from "srvx";
5
5
  import { terminalLink } from "termi-link";
6
6
  import * as apiServerCLIConfig from "@cedarjs/api-server/apiCliConfig";
7
7
  import * as bothServerCLIConfig from "@cedarjs/api-server/bothCliConfig";
@@ -11,6 +11,35 @@ import * as webServerCLIConfig from "@cedarjs/web-server";
11
11
  import { getPaths, getConfig } from "../lib/index.js";
12
12
  import { serverFileExists } from "../lib/project.js";
13
13
  import { webSsrServerHandler } from "./serveWebHandler.js";
14
+ function resolveUDEntryPath() {
15
+ const base = path.join(getPaths().api.dist, "ud", "index");
16
+ for (const ext of [".mjs", ".js"]) {
17
+ const entryPath = base + ext;
18
+ if (fs.existsSync(entryPath)) {
19
+ return entryPath;
20
+ }
21
+ }
22
+ return null;
23
+ }
24
+ async function startUDServer(entryPath, host, port) {
25
+ const mod = await import(pathToFileURL(entryPath).href);
26
+ const fetchable = mod.default ?? mod;
27
+ if (!fetchable || typeof fetchable.fetch !== "function") {
28
+ throw new Error(
29
+ `UD entry at ${entryPath} does not export a Fetchable (\`export default { fetch }\`).`
30
+ );
31
+ }
32
+ const server = serveSrvx({
33
+ ...fetchable,
34
+ port,
35
+ hostname: host,
36
+ gracefulShutdown: false,
37
+ manual: true
38
+ });
39
+ server.serve();
40
+ await server.ready();
41
+ return server;
42
+ }
14
43
  const command = "serve [side]";
15
44
  const description = "Start a server for serving both the api and web sides";
16
45
  const builder = async (yargs) => {
@@ -43,14 +72,11 @@ const builder = async (yargs) => {
43
72
  );
44
73
  process.exit(1);
45
74
  }
46
- const udEntryPath = path.join(getPaths().api.dist, "ud", "index.js");
47
- if (!fs.existsSync(udEntryPath)) {
75
+ const udEntryPath = resolveUDEntryPath();
76
+ if (!udEntryPath) {
48
77
  console.error(
49
78
  c.error(
50
- `
51
- Universal Deploy server entry not found at ${udEntryPath}.
52
- Please run \`yarn cedar build --ud\` before serving.
53
- `
79
+ "\n Universal Deploy server entry not found. Please run `yarn cedar build --ud` before serving.\n"
54
80
  )
55
81
  );
56
82
  process.exit(1);
@@ -96,42 +122,11 @@ const builder = async (yargs) => {
96
122
  port: webPort,
97
123
  host: webHost
98
124
  });
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
125
  console.log(`Web server listening at http://${webHost}:${webPort}`);
131
126
  process.stdout.write(
132
127
  `API server starting at http://${apiHost}:${apiPort}...`
133
128
  );
134
- await waitForPort(apiHost, apiPort);
129
+ await startUDServer(udEntryPath, apiHost, apiPort);
135
130
  process.stdout.write(
136
131
  `\rAPI server listening at http://${apiHost}:${apiPort}
137
132
  `
@@ -177,61 +172,25 @@ const builder = async (yargs) => {
177
172
  apiRootPath: argv.apiRootPath
178
173
  });
179
174
  if (argv.ud) {
180
- const udEntryPath = path.join(getPaths().api.dist, "ud", "index.js");
181
- if (!fs.existsSync(udEntryPath)) {
175
+ const udEntryPath = resolveUDEntryPath();
176
+ if (!udEntryPath) {
182
177
  console.error(
183
178
  c.error(
184
- `
185
- Universal Deploy server entry not found at ${udEntryPath}.
186
- Please run \`yarn cedar build --ud\` before serving.
187
- `
179
+ "\n Universal Deploy server entry not found. Please run `yarn cedar build --ud` before serving.\n"
188
180
  )
189
181
  );
190
182
  process.exit(1);
191
183
  }
192
- const udArgs = [];
193
- if (argv.port) {
194
- udArgs.push("--port", String(argv.port));
195
- }
196
- if (argv.host) {
197
- udArgs.push("--host", argv.host);
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
184
  const apiPort = argv.port ?? parseInt(process.env.PORT ?? "8911", 10);
217
185
  const apiHost = argv.host ?? process.env.HOST ?? "localhost";
218
186
  process.stdout.write(
219
187
  `API server starting at http://${apiHost}:${apiPort}...`
220
188
  );
221
- await waitForPort(apiHost, apiPort);
189
+ await startUDServer(udEntryPath, apiHost, apiPort);
222
190
  process.stdout.write(
223
191
  `\rAPI server listening at http://${apiHost}:${apiPort}
224
192
  `
225
193
  );
226
- await new Promise((resolve, reject) => {
227
- child.on("exit", (code) => {
228
- if (code !== 0) {
229
- reject(new Error(`UD server exited with code ${code}`));
230
- } else {
231
- resolve();
232
- }
233
- });
234
- });
235
194
  return;
236
195
  }
237
196
  if (serverFileExists()) {
@@ -296,14 +255,11 @@ const builder = async (yargs) => {
296
255
  process.exit(1);
297
256
  }
298
257
  if (argv.ud) {
299
- const udEntryPath = path.join(getPaths().api.dist, "ud", "index.js");
300
- if (!fs.existsSync(udEntryPath)) {
258
+ const udEntryPath = resolveUDEntryPath();
259
+ if (!udEntryPath) {
301
260
  console.error(
302
261
  c.error(
303
- `
304
- Universal Deploy server entry not found at ${udEntryPath}.
305
- Please run \`yarn cedar build --ud\` before serving.
306
- `
262
+ "\n Universal Deploy server entry not found. Please run `yarn cedar build --ud` before serving.\n"
307
263
  )
308
264
  );
309
265
  process.exit(1);
@@ -320,14 +276,11 @@ const builder = async (yargs) => {
320
276
  process.exit(1);
321
277
  }
322
278
  if (argv.ud) {
323
- const udEntryPath = path.join(getPaths().api.dist, "ud", "index.js");
324
- if (!fs.existsSync(udEntryPath)) {
279
+ const udEntryPath = resolveUDEntryPath();
280
+ if (!udEntryPath) {
325
281
  console.error(
326
282
  c.error(
327
- `
328
- Universal Deploy server entry not found at ${udEntryPath}.
329
- Please run \`yarn cedar build --ud\` before serving.
330
- `
283
+ "\n Universal Deploy server entry not found. Please run `yarn cedar build --ud` before serving.\n"
331
284
  )
332
285
  );
333
286
  process.exit(1);
@@ -372,34 +325,6 @@ function webSideIsBuilt(isStreamingOrRSC) {
372
325
  return fs.existsSync(path.join(getPaths().web.dist, "index.html"));
373
326
  }
374
327
  }
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
- }
403
328
  export {
404
329
  builder,
405
330
  command,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cedarjs/cli",
3
- "version": "5.0.0-canary.2341",
3
+ "version": "5.0.0-canary.2347",
4
4
  "description": "The CedarJS Command Line",
5
5
  "repository": {
6
6
  "type": "git",
@@ -33,17 +33,17 @@
33
33
  "dependencies": {
34
34
  "@babel/parser": "7.29.3",
35
35
  "@babel/preset-typescript": "7.28.5",
36
- "@cedarjs/api-server": "5.0.0-canary.2341",
37
- "@cedarjs/cli-helpers": "5.0.0-canary.2341",
38
- "@cedarjs/fastify-web": "5.0.0-canary.2341",
39
- "@cedarjs/internal": "5.0.0-canary.2341",
40
- "@cedarjs/prerender": "5.0.0-canary.2341",
41
- "@cedarjs/project-config": "5.0.0-canary.2341",
42
- "@cedarjs/structure": "5.0.0-canary.2341",
43
- "@cedarjs/telemetry": "5.0.0-canary.2341",
44
- "@cedarjs/utils": "5.0.0-canary.2341",
45
- "@cedarjs/vite": "5.0.0-canary.2341",
46
- "@cedarjs/web-server": "5.0.0-canary.2341",
36
+ "@cedarjs/api-server": "5.0.0-canary.2347",
37
+ "@cedarjs/cli-helpers": "5.0.0-canary.2347",
38
+ "@cedarjs/fastify-web": "5.0.0-canary.2347",
39
+ "@cedarjs/internal": "5.0.0-canary.2347",
40
+ "@cedarjs/prerender": "5.0.0-canary.2347",
41
+ "@cedarjs/project-config": "5.0.0-canary.2347",
42
+ "@cedarjs/structure": "5.0.0-canary.2347",
43
+ "@cedarjs/telemetry": "5.0.0-canary.2347",
44
+ "@cedarjs/utils": "5.0.0-canary.2347",
45
+ "@cedarjs/vite": "5.0.0-canary.2347",
46
+ "@cedarjs/web-server": "5.0.0-canary.2347",
47
47
  "@listr2/prompt-adapter-enquirer": "4.2.1",
48
48
  "@opentelemetry/api": "1.9.0",
49
49
  "@opentelemetry/core": "1.30.1",