@cedarjs/cli 2.8.0 → 2.8.1-next.109

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 (36) hide show
  1. package/dist/commands/build/buildHandler.js +7 -3
  2. package/dist/commands/build.js +2 -1
  3. package/dist/commands/check.js +2 -4
  4. package/dist/commands/console.js +2 -2
  5. package/dist/commands/consoleHandler.js +10 -4
  6. package/dist/commands/dev/devHandler.js +1 -4
  7. package/dist/commands/execHandler.js +11 -4
  8. package/dist/commands/generate/dataMigration/dataMigration.js +1 -2
  9. package/dist/commands/generate/realtime/realtimeHandler.js +3 -3
  10. package/dist/commands/generate/service/serviceHandler.js +1 -2
  11. package/dist/commands/generate.js +8 -1
  12. package/dist/commands/jobsHandler.js +4 -2
  13. package/dist/commands/lint.js +2 -2
  14. package/dist/commands/prerenderHandler.js +65 -35
  15. package/dist/commands/prismaHandler.js +41 -18
  16. package/dist/commands/setup/deploy/providers/coherenceHandler.js +3 -3
  17. package/dist/commands/setup/deploy/providers/flightcontrolHandler.js +4 -12
  18. package/dist/commands/setup/deploy/providers/renderHandler.js +5 -12
  19. package/dist/commands/setup/jobs/jobsHandler.js +3 -4
  20. package/dist/commands/setup/realtime/realtime.js +1 -1
  21. package/dist/commands/setup/realtime/realtimeHandler.js +20 -1
  22. package/dist/commands/setup/ui/libraries/tailwindcssHandler.js +1 -1
  23. package/dist/commands/test/datasourceWarning.js +42 -0
  24. package/dist/commands/{testHandler.js → test/testHandler.js} +43 -30
  25. package/dist/commands/{testHandlerEsm.js → test/testHandlerEsm.js} +38 -23
  26. package/dist/commands/test.js +5 -1
  27. package/dist/commands/testEsm.js +5 -1
  28. package/dist/commands/type-checkHandler.js +21 -12
  29. package/dist/commands/upgrade/upgradeHandler.js +22 -9
  30. package/dist/lib/background.js +2 -0
  31. package/dist/lib/generatePrismaClient.js +4 -4
  32. package/dist/lib/schemaHelpers.js +3 -6
  33. package/dist/lib/test.js +10 -0
  34. package/dist/telemetry/resource.js +1 -3
  35. package/dist/testLib/cells.js +5 -3
  36. package/package.json +17 -19
@@ -4,13 +4,10 @@ import path from "path";
4
4
  import prismaInternals from "@prisma/internals";
5
5
  import { Listr } from "listr2";
6
6
  import { recordTelemetryAttributes } from "@cedarjs/cli-helpers";
7
+ import { getPaths, getPrismaSchemas } from "@cedarjs/project-config";
7
8
  import { errorTelemetry } from "@cedarjs/telemetry";
8
9
  import c from "../../../../lib/colors.js";
9
- import {
10
- getPaths,
11
- writeFilesTask,
12
- printSetupNotes
13
- } from "../../../../lib/index.js";
10
+ import { writeFilesTask, printSetupNotes } from "../../../../lib/index.js";
14
11
  import { updateApiURLTask } from "../helpers/index.js";
15
12
  import {
16
13
  flightcontrolConfig,
@@ -18,7 +15,7 @@ import {
18
15
  postgresDatabaseService,
19
16
  mysqlDatabaseService
20
17
  } from "../templates/flightcontrol.js";
21
- const { getSchemaWithPath, getConfig } = prismaInternals;
18
+ const { getConfig } = prismaInternals;
22
19
  const getFlightcontrolJson = async (database) => {
23
20
  if (database === "none") {
24
21
  return {
@@ -26,12 +23,7 @@ const getFlightcontrolJson = async (database) => {
26
23
  content: flightcontrolConfig
27
24
  };
28
25
  }
29
- if (!fs.existsSync(path.join(getPaths().base, "api/db/schema.prisma"))) {
30
- throw new Error("Could not find prisma schema at 'api/db/schema.prisma'");
31
- }
32
- const result = await getSchemaWithPath(
33
- path.join(getPaths().base, "api/db/schema.prisma")
34
- );
26
+ const result = await getPrismaSchemas();
35
27
  const config = await getConfig({ datamodel: result.schemas });
36
28
  const detectedDatabase = config.datasources[0].activeProvider;
37
29
  if (detectedDatabase === database) {
@@ -1,15 +1,11 @@
1
- import fs from "node:fs";
2
1
  import path from "path";
3
2
  import prismaInternals from "@prisma/internals";
4
3
  import { Listr } from "listr2";
5
4
  import { recordTelemetryAttributes } from "@cedarjs/cli-helpers";
5
+ import { getPaths, getPrismaSchemas } from "@cedarjs/project-config";
6
6
  import { errorTelemetry } from "@cedarjs/telemetry";
7
7
  import c from "../../../../lib/colors.js";
8
- import {
9
- getPaths,
10
- writeFilesTask,
11
- printSetupNotes
12
- } from "../../../../lib/index.js";
8
+ import { writeFilesTask, printSetupNotes } from "../../../../lib/index.js";
13
9
  import { addFilesTask, updateApiURLTask } from "../helpers/index.js";
14
10
  import {
15
11
  POSTGRES_YAML,
@@ -17,7 +13,7 @@ import {
17
13
  RENDER_YAML,
18
14
  SQLITE_YAML
19
15
  } from "../templates/render.js";
20
- const { getSchemaWithPath, getConfig } = prismaInternals;
16
+ const { getConfig } = prismaInternals;
21
17
  const getRenderYamlContent = async (database) => {
22
18
  if (database === "none") {
23
19
  return {
@@ -25,11 +21,8 @@ const getRenderYamlContent = async (database) => {
25
21
  content: RENDER_YAML("")
26
22
  };
27
23
  }
28
- if (!fs.existsSync("api/db/schema.prisma")) {
29
- throw new Error("Could not find prisma schema at 'api/db/schema.prisma'");
30
- }
31
- const { schemas } = await getSchemaWithPath("api/db/schema.prisma");
32
- const config = await getConfig({ datamodel: schemas });
24
+ const result = await getPrismaSchemas();
25
+ const config = await getConfig({ datamodel: result.schemas });
33
26
  const detectedDatabase = config.datasources[0].activeProvider;
34
27
  if (detectedDatabase === database) {
35
28
  switch (database) {
@@ -3,11 +3,11 @@ import * as path from "node:path";
3
3
  import prismaInternals from "@prisma/internals";
4
4
  import { Listr } from "listr2";
5
5
  import { addApiPackages } from "@cedarjs/cli-helpers";
6
- import { getSchemaPath } from "@cedarjs/project-config";
6
+ import { getSchemaPath, getPrismaSchemas } from "@cedarjs/project-config";
7
7
  import c from "../../../lib/colors.js";
8
8
  import { getPaths, transformTSToJS, writeFile } from "../../../lib/index.js";
9
9
  import { isTypeScriptProject } from "../../../lib/project.js";
10
- const { getDMMF, getSchemaWithPath } = prismaInternals;
10
+ const { getDMMF } = prismaInternals;
11
11
  const MODEL_SCHEMA = `
12
12
  model BackgroundJob {
13
13
  id Int @id @default(autoincrement())
@@ -26,8 +26,7 @@ model BackgroundJob {
26
26
  }
27
27
  `;
28
28
  const getModelNames = async () => {
29
- const schemaPath = await getSchemaPath(getPaths().api.prismaConfig);
30
- const { schemas } = await getSchemaWithPath(schemaPath);
29
+ const { schemas } = await getPrismaSchemas();
31
30
  const schema = await getDMMF({ datamodel: schemas });
32
31
  return schema.datamodel.models.map((model) => model.name);
33
32
  };
@@ -4,7 +4,7 @@ const description = "Setup RedwoodJS Realtime";
4
4
  function builder(yargs) {
5
5
  yargs.option("includeExamples", {
6
6
  alias: ["e", "examples"],
7
- default: true,
7
+ default: void 0,
8
8
  description: "Include examples of how to implement liveQueries and subscriptions",
9
9
  type: "boolean"
10
10
  }).option("force", {
@@ -2,6 +2,7 @@ import fs from "node:fs";
2
2
  import path from "path";
3
3
  import execa from "execa";
4
4
  import { Listr } from "listr2";
5
+ import prompts from "prompts";
5
6
  import { addApiPackages } from "@cedarjs/cli-helpers";
6
7
  import { projectIsEsm } from "@cedarjs/project-config";
7
8
  import { errorTelemetry } from "@cedarjs/telemetry";
@@ -16,13 +17,31 @@ const { version } = JSON.parse(
16
17
  "utf-8"
17
18
  )
18
19
  );
19
- async function handler({ force, includeExamples, verbose }) {
20
+ async function handleExamplesPreference(includeExamples) {
21
+ let incl = includeExamples;
22
+ if (typeof includeExamples === "undefined") {
23
+ const response = await prompts({
24
+ type: "toggle",
25
+ name: "includeExamples",
26
+ message: "Do you want to generate examples?",
27
+ initial: true,
28
+ active: "Yes",
29
+ inactive: "No"
30
+ });
31
+ incl = response.includeExamples;
32
+ }
33
+ return incl;
34
+ }
35
+ async function handler(args) {
20
36
  const redwoodPaths = getPaths();
21
37
  const ts = isTypeScriptProject();
22
38
  const realtimeLibFilePath = path.join(
23
39
  redwoodPaths.api.lib,
24
40
  `realtime.${isTypeScriptProject() ? "ts" : "js"}`
25
41
  );
42
+ const force = args.force || false;
43
+ const verbose = args.verbose || false;
44
+ const includeExamples = await handleExamplesPreference(args.includeExamples);
26
45
  const tasks = new Listr(
27
46
  [
28
47
  addApiPackages(["ioredis@^5", `@cedarjs/realtime@${version}`]),
@@ -76,7 +76,7 @@ const handler = async ({ force, install }) => {
76
76
  install
77
77
  });
78
78
  const rwPaths = getPaths();
79
- const projectPackages = ["prettier-plugin-tailwindcss@^0.5.12"];
79
+ const projectPackages = ["prettier-plugin-tailwindcss@^0.7.0"];
80
80
  const webWorkspacePackages = [
81
81
  "postcss",
82
82
  "postcss-loader",
@@ -0,0 +1,42 @@
1
+ import fs from "node:fs";
2
+ import Enquirer from "enquirer";
3
+ import { getPaths } from "@cedarjs/project-config";
4
+ async function warnIfNonStandardDatasourceUrl({ force } = {}) {
5
+ const cedarPaths = getPaths();
6
+ if (!fs.existsSync(cedarPaths.api.prismaConfig)) {
7
+ return;
8
+ }
9
+ const prismaConfig = await fs.promises.readFile(
10
+ cedarPaths.api.prismaConfig,
11
+ "utf-8"
12
+ );
13
+ const prismaConfigLines = prismaConfig.split("\n");
14
+ for (const line of prismaConfigLines) {
15
+ const envVarName = (line.match(
16
+ /^\s*url: process\.env\.(\w+),?(\s*\/\/.*)?$/
17
+ ) ?? line.match(/^\s*url: env\(['"](\w+)['"]\),?(\s*\/\/.*)?$/) ?? line.match(/[{,] url: process\.env\.(\w+)(?:,| })/) ?? line.match(/[{,] url: env\(['"](\w+)['"]\)(?:,| })/))?.[1];
18
+ if (envVarName && envVarName !== "DATABASE_URL") {
19
+ if (force) {
20
+ return;
21
+ }
22
+ console.warn(
23
+ `Found a non-standard prisma config datasource url env var: "${envVarName}".
24
+ Cedar will not override this env var, potentially running destructive commands against your production database.`
25
+ );
26
+ const { proceed } = await Enquirer.prompt({
27
+ type: "confirm",
28
+ name: "proceed",
29
+ message: "Are you sure you want to run tests against this database?",
30
+ initial: false
31
+ });
32
+ if (!proceed) {
33
+ console.log("Aborting.");
34
+ process.exit(1);
35
+ }
36
+ return;
37
+ }
38
+ }
39
+ }
40
+ export {
41
+ warnIfNonStandardDatasourceUrl
42
+ };
@@ -1,12 +1,22 @@
1
1
  import fs from "node:fs";
2
- import path from "path";
2
+ import path from "node:path";
3
3
  import execa from "execa";
4
4
  import { recordTelemetryAttributes } from "@cedarjs/cli-helpers";
5
5
  import { ensurePosixPath } from "@cedarjs/project-config";
6
6
  import { errorTelemetry, timedTelemetry } from "@cedarjs/telemetry";
7
- import c from "../lib/colors.js";
8
- import { getPaths } from "../lib/index.js";
9
- import * as project from "../lib/project.js";
7
+ import c from "../../lib/colors.js";
8
+ import { getPaths } from "../../lib/index.js";
9
+ import * as project from "../../lib/project.js";
10
+ import { warnIfNonStandardDatasourceUrl } from "./datasourceWarning.js";
11
+ function hasStringMessage(value) {
12
+ return typeof value === "object" && value !== null && "message" in value && value.message === "string";
13
+ }
14
+ function getExitCode(value) {
15
+ if (!value || typeof value !== "object" || !("exitCode" in value) || typeof value.exitCode !== "number") {
16
+ return void 0;
17
+ }
18
+ return value.exitCode;
19
+ }
10
20
  function isInGitRepository() {
11
21
  try {
12
22
  execa.commandSync("git rev-parse --is-inside-work-tree");
@@ -24,25 +34,24 @@ function isInMercurialRepository() {
24
34
  }
25
35
  }
26
36
  function isJestConfigFile(sides) {
27
- for (let side of sides) {
37
+ for (const side of sides) {
28
38
  try {
29
- if (sides.includes(side)) {
30
- const jestConfigExists = fs.existsSync(path.join(side, "jest.config.js")) || fs.existsSync(path.join(side, "jest.config.ts"));
31
- if (!jestConfigExists) {
32
- console.error(
33
- c.error(
34
- `
39
+ const jestConfigExists = fs.existsSync(path.join(side, "jest.config.js")) || fs.existsSync(path.join(side, "jest.config.ts"));
40
+ if (!jestConfigExists) {
41
+ console.error(
42
+ c.error(
43
+ `
35
44
  Error: Missing Jest config file ${side}/jest.config.js
36
45
  To add this file, run \`npx @cedarjs/codemods update-jest-config\`
37
46
  `
38
- )
39
- );
40
- throw new Error(`Error: Jest config file not found in ${side} side`);
41
- }
47
+ )
48
+ );
49
+ throw new Error(`Error: Jest config file not found in ${side} side`);
42
50
  }
43
- } catch (e) {
44
- errorTelemetry(process.argv, e.message);
45
- process.exit(e?.exitCode || 1);
51
+ } catch (error) {
52
+ const message = hasStringMessage(error) ? error.message : `Error: Jest config file not found in ${side} side`;
53
+ errorTelemetry(process.argv, message);
54
+ process.exit(getExitCode(error) ?? 1);
46
55
  }
47
56
  }
48
57
  }
@@ -51,6 +60,7 @@ const handler = async ({
51
60
  watch = true,
52
61
  collectCoverage = false,
53
62
  dbPush = true,
63
+ force = false,
54
64
  ...others
55
65
  }) => {
56
66
  recordTelemetryAttributes({
@@ -64,21 +74,20 @@ const handler = async ({
64
74
  if ([
65
75
  "collect-coverage",
66
76
  "db-push",
77
+ "force",
67
78
  "loadEnvFiles",
68
79
  "watch",
69
80
  "$0",
70
81
  "_"
71
82
  ].includes(flagName)) {
72
83
  return [];
73
- } else {
74
- const flag = flagName.length > 1 ? `--${flagName}` : `-${flagName}`;
75
- const flagValue = others[flagName];
76
- if (Array.isArray(flagValue)) {
77
- return flagValue.flatMap((val) => [flag, val]);
78
- } else {
79
- return [flag, flagValue];
80
- }
81
84
  }
85
+ const flag = flagName.length > 1 ? `--${flagName}` : `-${flagName}`;
86
+ const flagValue = others[flagName];
87
+ if (Array.isArray(flagValue)) {
88
+ return flagValue.flatMap((val) => [flag, val]);
89
+ }
90
+ return [flag, flagValue];
82
91
  });
83
92
  const sides = filterParams.filter(
84
93
  (filterString) => project.workspaces().includes(filterString)
@@ -113,11 +122,14 @@ const handler = async ({
113
122
  if (sides.includes("api") && !dbPush) {
114
123
  process.env.SKIP_DB_PUSH = "1";
115
124
  }
125
+ if (sides.includes("api")) {
126
+ await warnIfNonStandardDatasourceUrl({ force });
127
+ }
116
128
  const runCommand = async () => {
117
129
  await execa("yarn", ["jest", ...jestArgs], {
118
130
  cwd: rwjsPaths.base,
119
131
  stdio: "inherit",
120
- env: { DATABASE_URL }
132
+ env: { ...process.env, DATABASE_URL }
121
133
  });
122
134
  };
123
135
  if (watch) {
@@ -127,9 +139,10 @@ const handler = async ({
127
139
  await runCommand();
128
140
  });
129
141
  }
130
- } catch (e) {
131
- errorTelemetry(process.argv, e.message);
132
- process.exit(e?.exitCode || 1);
142
+ } catch (error) {
143
+ const message = hasStringMessage(error) ? error.message : "Test command failed";
144
+ errorTelemetry(process.argv, message);
145
+ process.exit(getExitCode(error) ?? 1);
133
146
  }
134
147
  };
135
148
  export {
@@ -2,11 +2,22 @@ import execa from "execa";
2
2
  import { recordTelemetryAttributes } from "@cedarjs/cli-helpers";
3
3
  import { ensurePosixPath } from "@cedarjs/project-config";
4
4
  import { errorTelemetry, timedTelemetry } from "@cedarjs/telemetry";
5
- import { getPaths } from "../lib/index.js";
6
- import * as project from "../lib/project.js";
5
+ import { getPaths } from "../../lib/index.js";
6
+ import * as project from "../../lib/project.js";
7
+ import { warnIfNonStandardDatasourceUrl } from "./datasourceWarning.js";
8
+ function hasStringMessage(value) {
9
+ return typeof value === "object" && value !== null && "message" in value && value.message === "string";
10
+ }
11
+ function getExitCode(value) {
12
+ if (!value || typeof value !== "object" || !("exitCode" in value) || typeof value.exitCode !== "number") {
13
+ return void 0;
14
+ }
15
+ return value.exitCode;
16
+ }
7
17
  const handler = async ({
8
18
  filter: filterParams = [],
9
19
  dbPush = true,
20
+ force = false,
10
21
  ...others
11
22
  }) => {
12
23
  recordTelemetryAttributes({
@@ -16,22 +27,20 @@ const handler = async ({
16
27
  let watch = true;
17
28
  const rwjsPaths = getPaths();
18
29
  const forwardVitestFlags = Object.keys(others).flatMap((flagName) => {
19
- if (["db-push", "loadEnvFiles", "$0", "_"].includes(flagName)) {
30
+ if (["db-push", "force", "loadEnvFiles", "$0", "_"].includes(flagName)) {
20
31
  return [];
21
- } else {
22
- const flag = flagName.length > 1 ? `--${flagName}` : `-${flagName}`;
23
- const flagValue = others[flagName];
24
- if (flagName === "watch") {
25
- watch = flagValue === true;
26
- } else if (flagName === "run" && flagValue) {
27
- watch = false;
28
- }
29
- if (Array.isArray(flagValue)) {
30
- return flagValue.flatMap((val) => [flag, val]);
31
- } else {
32
- return [flag, flagValue];
33
- }
34
32
  }
33
+ const flag = flagName.length > 1 ? `--${flagName}` : `-${flagName}`;
34
+ const flagValue = others[flagName];
35
+ if (flagName === "watch") {
36
+ watch = flagValue === true;
37
+ } else if (flagName === "run" && flagValue) {
38
+ watch = false;
39
+ }
40
+ if (Array.isArray(flagValue)) {
41
+ return flagValue.flatMap((val) => [flag, val]);
42
+ }
43
+ return [flag, flagValue];
35
44
  });
36
45
  const sides = filterParams.filter(
37
46
  (filterString) => project.workspaces().includes(filterString)
@@ -49,10 +58,12 @@ const handler = async ({
49
58
  if (process.env.CI) {
50
59
  vitestArgs.push("--run");
51
60
  }
52
- if (!sides.length) {
53
- project.workspaces().forEach((side) => sides.push(side));
61
+ if (!others["config"]) {
62
+ if (!sides.length) {
63
+ project.workspaces().forEach((side) => sides.push(side));
64
+ }
65
+ sides.forEach((side) => vitestArgs.push("--project", side));
54
66
  }
55
- sides.forEach((side) => vitestArgs.push("--project", side));
56
67
  try {
57
68
  const cacheDirDb = `file:${ensurePosixPath(
58
69
  rwjsPaths.generated.base
@@ -61,11 +72,14 @@ const handler = async ({
61
72
  if (sides.includes("api") && !dbPush) {
62
73
  process.env.SKIP_DB_PUSH = "1";
63
74
  }
75
+ if (sides.includes("api")) {
76
+ await warnIfNonStandardDatasourceUrl({ force });
77
+ }
64
78
  const runCommand = async () => {
65
79
  await execa("yarn", ["vitest", ...vitestArgs], {
66
80
  cwd: rwjsPaths.base,
67
81
  stdio: "inherit",
68
- env: { DATABASE_URL }
82
+ env: { ...process.env, DATABASE_URL }
69
83
  });
70
84
  };
71
85
  if (watch) {
@@ -75,9 +89,10 @@ const handler = async ({
75
89
  await runCommand();
76
90
  });
77
91
  }
78
- } catch (e) {
79
- errorTelemetry(process.argv, e.message);
80
- process.exit(e?.exitCode || 1);
92
+ } catch (error) {
93
+ const message = hasStringMessage(error) ? error.message : "Test command failed";
94
+ errorTelemetry(process.argv, message);
95
+ process.exit(getExitCode(error) ?? 1);
81
96
  }
82
97
  };
83
98
  export {
@@ -21,6 +21,10 @@ const builder = (yargs) => {
21
21
  describe: "Syncs the test database with your Prisma schema without requiring a migration. It creates a test database if it doesn't already exist.",
22
22
  type: "boolean",
23
23
  default: true
24
+ }).option("force", {
25
+ describe: "Run tests without prompting for confirmation, even when a non-standard datasource url env var is detected.",
26
+ type: "boolean",
27
+ default: false
24
28
  }).epilogue(
25
29
  `For all available flags, run jest cli directly ${c.tip(
26
30
  "yarn jest --help"
@@ -34,7 +38,7 @@ Also see the ${terminalLink(
34
38
  );
35
39
  };
36
40
  const handler = async (options) => {
37
- const { handler: handler2 } = await import("./testHandler.js");
41
+ const { handler: handler2 } = await import("./test/testHandler.js");
38
42
  return handler2(options);
39
43
  };
40
44
  export {
@@ -18,6 +18,10 @@ const builder = (yargs) => {
18
18
  describe: "Syncs the test database with your Prisma schema without requiring a migration. It creates a test database if it doesn't already exist.",
19
19
  type: "boolean",
20
20
  default: true
21
+ }).option("force", {
22
+ describe: "Skip any confirmation prompts and run tests without interruption. Useful in CI or scripted environments.",
23
+ type: "boolean",
24
+ default: false
21
25
  }).epilogue(
22
26
  `For all available flags, run vitest cli directly ${vitestTip}
23
27
 
@@ -26,7 +30,7 @@ Also see the ${cliDocsLink}
26
30
  );
27
31
  };
28
32
  const handler = async (options) => {
29
- const { handler: handler2 } = await import("./testHandlerEsm.js");
33
+ const { handler: handler2 } = await import("./test/testHandlerEsm.js");
30
34
  return handler2(options);
31
35
  };
32
36
  export {
@@ -1,25 +1,36 @@
1
- import path from "path";
1
+ import path from "node:path";
2
2
  import concurrently from "concurrently";
3
3
  import execa from "execa";
4
4
  import { Listr } from "listr2";
5
5
  import { recordTelemetryAttributes } from "@cedarjs/cli-helpers";
6
6
  import { generatePrismaClient } from "../lib/generatePrismaClient.js";
7
7
  import { getPaths } from "../lib/index.js";
8
- const handler = async ({ sides, verbose, prisma, generate }) => {
8
+ const isConcurrentlyErrorArray = (value) => {
9
+ return Array.isArray(value);
10
+ };
11
+ const handler = async ({
12
+ sides,
13
+ verbose = false,
14
+ prisma = true,
15
+ generate = true
16
+ }) => {
17
+ const selectedSides = (Array.isArray(sides) ? sides : []).filter(
18
+ (side) => typeof side === "string"
19
+ );
9
20
  recordTelemetryAttributes({
10
21
  command: "type-check",
11
- sides: JSON.stringify(sides),
22
+ sides: JSON.stringify(selectedSides),
12
23
  verbose,
13
24
  prisma,
14
25
  generate
15
26
  });
16
27
  const typeCheck = async () => {
17
28
  let conclusiveExitCode = 0;
18
- const tscForAllSides = sides.map((side) => {
29
+ const tscForAllSides = selectedSides.map((side) => {
19
30
  const projectDir = path.join(getPaths().base, side);
20
31
  return {
21
32
  cwd: projectDir,
22
- command: `yarn tsc --noEmit --skipLibCheck`
33
+ command: "yarn tsc --noEmit --skipLibCheck"
23
34
  };
24
35
  });
25
36
  const { result } = concurrently(tscForAllSides, {
@@ -28,18 +39,16 @@ const handler = async ({ sides, verbose, prisma, generate }) => {
28
39
  });
29
40
  try {
30
41
  await result;
31
- } catch (err) {
32
- if (err.length) {
33
- const exitCodes = err.map((e) => e?.exitCode).filter(Boolean);
42
+ } catch (error) {
43
+ if (isConcurrentlyErrorArray(error)) {
44
+ const exitCodes = error.map((entry) => entry.exitCode).filter((exitCode2) => Boolean(exitCode2));
34
45
  conclusiveExitCode = Math.max(...exitCodes);
35
46
  }
36
47
  }
37
48
  return conclusiveExitCode;
38
49
  };
39
50
  if (generate && prisma) {
40
- await generatePrismaClient({
41
- verbose
42
- });
51
+ await generatePrismaClient({ verbose });
43
52
  }
44
53
  if (generate) {
45
54
  await new Listr(
@@ -53,7 +62,7 @@ const handler = async ({ sides, verbose, prisma, generate }) => {
53
62
  }
54
63
  ],
55
64
  {
56
- renderer: verbose && "verbose",
65
+ renderer: verbose ? "verbose" : "default",
57
66
  rendererOptions: { collapseSubtasks: false }
58
67
  }
59
68
  ).run();
@@ -331,6 +331,11 @@ async function updatePackageVersionsFromTemplate(ctx, { dryRun, verbose }) {
331
331
  title: `Updating ${pkgJsonPath}`,
332
332
  task: async (_ctx, task) => {
333
333
  const res = await fetch(url);
334
+ if (!res.ok) {
335
+ throw new Error(
336
+ `Failed to fetch template package.json from ${url}: ` + res.statusText
337
+ );
338
+ }
334
339
  const text = await res.text();
335
340
  const templatePackageJson = JSON.parse(text);
336
341
  const localPackageJsonText = fs.readFileSync(pkgJsonPath, "utf-8");
@@ -380,16 +385,19 @@ async function downloadYarnPatches(ctx, { dryRun, verbose }) {
380
385
  throw new Error("Failed to upgrade");
381
386
  }
382
387
  const githubToken = process.env.GH_TOKEN || process.env.GITHUB_TOKEN || process.env.REDWOOD_GITHUB_TOKEN;
383
- const res = await fetch(
384
- "https://api.github.com/repos/cedarjs/cedar/git/trees/main?recursive=1",
385
- {
386
- headers: {
387
- ...githubToken && { Authorization: `Bearer ${githubToken}` },
388
- ["X-GitHub-Api-Version"]: "2022-11-28",
389
- Accept: "application/vnd.github+json"
390
- }
388
+ const url = "https://api.github.com/repos/cedarjs/cedar/git/trees/main?recursive=1";
389
+ const res = await fetch(url, {
390
+ headers: {
391
+ ...githubToken && { Authorization: `Bearer ${githubToken}` },
392
+ ["X-GitHub-Api-Version"]: "2022-11-28",
393
+ Accept: "application/vnd.github+json"
391
394
  }
392
- );
395
+ });
396
+ if (!res.ok) {
397
+ throw new Error(
398
+ `Failed to fetch list of yarn patches from ${url}: ` + res.statusText
399
+ );
400
+ }
393
401
  const json = await res.json();
394
402
  const patches = json.tree?.filter(
395
403
  (patchInfo) => patchInfo.path.startsWith(
@@ -409,6 +417,11 @@ async function downloadYarnPatches(ctx, { dryRun, verbose }) {
409
417
  title: `Downloading ${patch.path}`,
410
418
  task: async () => {
411
419
  const res2 = await fetch(patch.url);
420
+ if (!res2.ok) {
421
+ throw new Error(
422
+ `Failed to fetch patch metadata from ${patch.url}: ` + res2.statusText
423
+ );
424
+ }
412
425
  const patchMeta = await res2.json();
413
426
  const patchPath = path.join(
414
427
  getPaths().base,
@@ -47,6 +47,8 @@ function spawnBackgroundProcess(name, cmd, args) {
47
47
  const child = spawn(cmd, args, spawnOptions);
48
48
  child.unref();
49
49
  }
50
+ fs.closeSync(stdout);
51
+ fs.closeSync(stderr);
50
52
  }
51
53
  export {
52
54
  spawnBackgroundProcess
@@ -1,7 +1,7 @@
1
1
  import fs from "node:fs";
2
2
  import { createRequire } from "node:module";
3
3
  import { resolveGeneratedPrismaClient } from "@cedarjs/project-config";
4
- import { runCommandTask, getPaths } from "../lib/index.js";
4
+ import { runCommandTask, getPaths } from "./index.js";
5
5
  const generatePrismaCommand = async () => {
6
6
  const createdRequire = createRequire(import.meta.url);
7
7
  const prismaIndexPath = createdRequire.resolve("prisma/build/index.js");
@@ -18,10 +18,10 @@ const generatePrismaClient = async ({
18
18
  verbose = true,
19
19
  force = true,
20
20
  silent = false
21
- }) => {
21
+ } = {}) => {
22
22
  if (!force) {
23
- const prismaClientPath = resolveGeneratedPrismaClient();
24
- const prismaClientFile = fs.existsSync(prismaClientPath) ? fs.readFileSync(prismaClientPath, "utf8") : "";
23
+ const { clientPath } = await resolveGeneratedPrismaClient();
24
+ const prismaClientFile = clientPath && fs.existsSync(clientPath) ? fs.readFileSync(clientPath, "utf8") : "";
25
25
  if (!prismaClientFile.includes("@prisma/client did not initialize yet.") && prismaClientFile.includes("exports.Prisma.")) {
26
26
  return;
27
27
  }
@@ -1,9 +1,8 @@
1
1
  import prismaInternals from "@prisma/internals";
2
- import { getSchemaPath } from "@cedarjs/project-config";
2
+ import { getPrismaSchemas } from "@cedarjs/project-config";
3
3
  import { singularize, isPlural } from "@cedarjs/utils/cedarPluralize";
4
4
  import { ensureUniquePlural } from "./pluralHelpers.js";
5
- import { getPaths } from "./index.js";
6
- const { getConfig, getDMMF, getSchemaWithPath } = prismaInternals;
5
+ const { getConfig, getDMMF } = prismaInternals;
7
6
  const schemaMemo = {};
8
7
  const getExistingModelName = async (name) => {
9
8
  if (!name) {
@@ -64,9 +63,7 @@ const getEnum = async (name) => {
64
63
  return model;
65
64
  };
66
65
  const getDataModel = async () => {
67
- const prismaConfigPath = getPaths().api.prismaConfig;
68
- const schemaPath = await getSchemaPath(prismaConfigPath);
69
- const result = await getSchemaWithPath(schemaPath);
66
+ const result = await getPrismaSchemas();
70
67
  return result.schemas;
71
68
  };
72
69
  const getSchemaDefinitions = async () => {