@cedarjs/cli 5.0.6 → 5.0.7-next.219
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/README.md +7 -10
- package/dist/cfw.js +3 -1
- package/dist/commands/build/buildHandler.js +14 -6
- package/dist/commands/console.js +5 -3
- package/dist/commands/dev/devHandler.js +34 -4
- package/dist/commands/dev.js +3 -0
- package/dist/commands/experimental/setupOpentelemetryHandler.js +1 -1
- package/dist/commands/generate/job/jobHandler.js +5 -7
- package/dist/commands/generate/package/packageHandler.js +3 -6
- package/dist/commands/generate/scaffold/scaffoldHandler.js +73 -4
- package/dist/commands/generate/sdl/sdlHandler.js +9 -33
- package/dist/commands/generate/yargsHandlerHelpers.js +0 -6
- package/dist/commands/lint.js +1 -61
- package/dist/commands/prismaHandler.js +3 -6
- package/dist/commands/serve.js +21 -22
- package/dist/commands/serveBothHandler.js +4 -4
- package/dist/commands/setup/auth/auth.js +1 -1
- package/dist/commands/setup/database/database.js +15 -0
- package/dist/commands/setup/database/postgres.js +19 -0
- package/dist/commands/setup/database/postgresHandler.js +194 -0
- package/dist/commands/setup/deploy/helpers/index.js +9 -39
- package/dist/commands/setup/deploy/providers/flightcontrolHandler.js +17 -5
- package/dist/commands/setup/deploy/providers/renderHandler.js +4 -20
- package/dist/commands/setup/deploy/templates/render.js +24 -14
- package/dist/commands/setup/docker/templates/Dockerfile.yarn +2 -5
- package/dist/commands/setup/docker/templates/docker-compose.dev.yml +1 -1
- package/dist/commands/setup/docker/templates/docker-compose.prod.yml +2 -5
- package/dist/commands/setup/graphql/features/fragments/appGqlConfigTransform.js +6 -3
- package/dist/commands/setup/neon/neonHandler.js +96 -254
- package/dist/commands/setup/ui/libraries/tailwindcssHandler.js +0 -1
- package/dist/commands/setup.js +2 -1
- package/dist/lib/exec.js +5 -8
- package/dist/lib/index.js +22 -6
- package/dist/lib/updateCheck.js +34 -6
- package/dist/telemetry/resource.js +3 -8
- package/package.json +20 -21
- package/dist/commands/consoleHandler.js +0 -75
- /package/dist/commands/setup/{neon → database}/templates/db.ts.template +0 -0
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import path from "path";
|
|
2
2
|
import concurrently from "concurrently";
|
|
3
|
-
import { handler as apiServerHandler } from "@cedarjs/api-server/
|
|
3
|
+
import { handler as apiServerHandler } from "@cedarjs/api-server/apiCliConfigHandler";
|
|
4
4
|
import {
|
|
5
5
|
getAPIHost,
|
|
6
6
|
getAPIPort,
|
|
7
7
|
getAPIRootPath,
|
|
8
8
|
getWebHost,
|
|
9
9
|
getWebPort
|
|
10
|
-
} from "@cedarjs/api-server/
|
|
10
|
+
} from "@cedarjs/api-server/cliHelpers";
|
|
11
11
|
import { formatRunBinCommand } from "@cedarjs/cli-helpers/packageManager/display";
|
|
12
12
|
import { runBin } from "@cedarjs/cli-helpers/packageManager/exec";
|
|
13
13
|
import { getConfig, getPaths } from "@cedarjs/project-config";
|
|
@@ -27,8 +27,8 @@ const bothServerFileHandler = async (argv) => {
|
|
|
27
27
|
} else {
|
|
28
28
|
argv.apiPort ??= getAPIPort();
|
|
29
29
|
argv.apiHost ??= getAPIHost();
|
|
30
|
-
argv.webPort ??= getWebPort();
|
|
31
|
-
argv.webHost ??= getWebHost();
|
|
30
|
+
argv.webPort ??= getWebPort({ isPublicSide: true });
|
|
31
|
+
argv.webHost ??= getWebHost({ isPublicSide: true });
|
|
32
32
|
const apiRootPath = argv.apiRootPath ?? getAPIRootPath();
|
|
33
33
|
const apiProxyTarget = [
|
|
34
34
|
"http://",
|
|
@@ -237,7 +237,7 @@ async function getAuthSetupHandler(module) {
|
|
|
237
237
|
});
|
|
238
238
|
}
|
|
239
239
|
const setupModule = await import(module);
|
|
240
|
-
return setupModule.
|
|
240
|
+
return setupModule.handler;
|
|
241
241
|
}
|
|
242
242
|
function isInstalled(module) {
|
|
243
243
|
const { dependencies, devDependencies } = JSON.parse(
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { terminalLink } from "termi-link";
|
|
2
|
+
import * as setupDatabasePostgres from "./postgres.js";
|
|
3
|
+
const command = "database <command>";
|
|
4
|
+
const description = "Switch your project's database";
|
|
5
|
+
const builder = (yargs) => yargs.command(setupDatabasePostgres).demandCommand().epilogue(
|
|
6
|
+
`Also see the ${terminalLink(
|
|
7
|
+
"CedarJS CLI Reference",
|
|
8
|
+
"https://cedarjs.com/docs/cli-commands#setup"
|
|
9
|
+
)}`
|
|
10
|
+
);
|
|
11
|
+
export {
|
|
12
|
+
builder,
|
|
13
|
+
command,
|
|
14
|
+
description
|
|
15
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { recordTelemetryAttributes } from "@cedarjs/cli-helpers";
|
|
2
|
+
const command = "postgres";
|
|
3
|
+
const description = "Switch your project from SQLite to PostgreSQL (schema, dependencies, and database adapter)";
|
|
4
|
+
function builder(yargs) {
|
|
5
|
+
return yargs;
|
|
6
|
+
}
|
|
7
|
+
async function handler() {
|
|
8
|
+
recordTelemetryAttributes({
|
|
9
|
+
command: "setup database postgres"
|
|
10
|
+
});
|
|
11
|
+
const { handler: handler2 } = await import("./postgresHandler.js");
|
|
12
|
+
return handler2();
|
|
13
|
+
}
|
|
14
|
+
export {
|
|
15
|
+
builder,
|
|
16
|
+
command,
|
|
17
|
+
description,
|
|
18
|
+
handler
|
|
19
|
+
};
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import execa from "execa";
|
|
4
|
+
import { Listr } from "listr2";
|
|
5
|
+
import { colors, getPaths, installPackages } from "@cedarjs/cli-helpers";
|
|
6
|
+
import { prettyPrintCedarCommand } from "@cedarjs/cli-helpers/packageManager";
|
|
7
|
+
import { addWorkspacePackages } from "@cedarjs/cli-helpers/packageManager/packages";
|
|
8
|
+
import { resolveFile } from "@cedarjs/project-config";
|
|
9
|
+
import { errorTelemetry } from "@cedarjs/telemetry";
|
|
10
|
+
function checkProjectShape(cedarPaths) {
|
|
11
|
+
const schemaPath = path.join(cedarPaths.api.base, "db", "schema.prisma");
|
|
12
|
+
const dbPath = resolveFile(path.join(cedarPaths.api.lib, "db"));
|
|
13
|
+
if (!fs.existsSync(schemaPath)) {
|
|
14
|
+
return blocked(`Could not find ${schemaPath}.`);
|
|
15
|
+
}
|
|
16
|
+
if (!dbPath) {
|
|
17
|
+
return blocked(`No ${path.join(cedarPaths.api.lib, "db")} file found`);
|
|
18
|
+
}
|
|
19
|
+
const schemaContent = fs.readFileSync(schemaPath, "utf-8");
|
|
20
|
+
const hasPgAdapter = fs.readFileSync(dbPath, "utf-8").includes("PrismaPg");
|
|
21
|
+
if (schemaContent.includes('provider = "postgresql"') && hasPgAdapter) {
|
|
22
|
+
return {
|
|
23
|
+
ok: false,
|
|
24
|
+
alreadyConverted: true,
|
|
25
|
+
message: "This project is already configured for PostgreSQL."
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
if (!schemaContent.includes('provider = "sqlite"') || hasPgAdapter) {
|
|
29
|
+
return blocked(
|
|
30
|
+
"This command only converts a project that is still on SQLite, with the default adapter in api/src/lib/db.ts (or db.js) untouched. This project doesn't match that shape (a different provider, or a partial previous conversion). Please switch it over to PostgreSQL manually."
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
return { ok: true, dbPath };
|
|
34
|
+
}
|
|
35
|
+
function blocked(message) {
|
|
36
|
+
return { ok: false, alreadyConverted: false, message };
|
|
37
|
+
}
|
|
38
|
+
function getSqliteToPostgresTasks({
|
|
39
|
+
dbPath
|
|
40
|
+
}) {
|
|
41
|
+
const cedarPaths = getPaths();
|
|
42
|
+
const schemaPath = path.join(cedarPaths.api.base, "db", "schema.prisma");
|
|
43
|
+
const rootPkgPath = path.join(cedarPaths.base, "package.json");
|
|
44
|
+
const apiPkgPath = path.join(cedarPaths.api.base, "package.json");
|
|
45
|
+
const dbTsTemplatePath = path.join(
|
|
46
|
+
import.meta.dirname,
|
|
47
|
+
"templates",
|
|
48
|
+
"db.ts.template"
|
|
49
|
+
);
|
|
50
|
+
return [
|
|
51
|
+
{
|
|
52
|
+
title: "Removing SQLite dependencies from api/package.json",
|
|
53
|
+
task: () => {
|
|
54
|
+
const pkg = JSON.parse(fs.readFileSync(apiPkgPath, "utf-8"));
|
|
55
|
+
if (pkg.dependencies) {
|
|
56
|
+
delete pkg.dependencies["better-sqlite3"];
|
|
57
|
+
delete pkg.dependencies["@prisma/adapter-better-sqlite3"];
|
|
58
|
+
}
|
|
59
|
+
fs.writeFileSync(apiPkgPath, JSON.stringify(pkg, null, 2) + "\n");
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
title: "Removing better-sqlite3 dependenciesMeta",
|
|
64
|
+
task: () => {
|
|
65
|
+
if (!fs.existsSync(rootPkgPath)) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
const pkg = JSON.parse(fs.readFileSync(rootPkgPath, "utf-8"));
|
|
69
|
+
if (pkg.dependenciesMeta?.["better-sqlite3"]) {
|
|
70
|
+
delete pkg.dependenciesMeta["better-sqlite3"];
|
|
71
|
+
if (Object.keys(pkg.dependenciesMeta).length === 0) {
|
|
72
|
+
delete pkg.dependenciesMeta;
|
|
73
|
+
}
|
|
74
|
+
fs.writeFileSync(rootPkgPath, JSON.stringify(pkg, null, 2) + "\n");
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
title: "Switching Prisma schema to PostgreSQL",
|
|
80
|
+
task: () => {
|
|
81
|
+
const schemaContent = fs.readFileSync(schemaPath, "utf-8");
|
|
82
|
+
fs.writeFileSync(
|
|
83
|
+
schemaPath,
|
|
84
|
+
schemaContent.replace(
|
|
85
|
+
'provider = "sqlite"',
|
|
86
|
+
'provider = "postgresql"'
|
|
87
|
+
)
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
title: "Updating database adapter",
|
|
93
|
+
task: () => {
|
|
94
|
+
const pgDbTs = fs.readFileSync(dbTsTemplatePath, "utf-8");
|
|
95
|
+
fs.writeFileSync(dbPath, pgDbTs);
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
title: "Adding required api packages...",
|
|
100
|
+
task: async () => {
|
|
101
|
+
await addWorkspacePackages("api", ["@prisma/adapter-pg@7.8.0"], {
|
|
102
|
+
cwd: cedarPaths.api.base
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
];
|
|
107
|
+
}
|
|
108
|
+
function readEnvVar(envContent, name) {
|
|
109
|
+
return envContent.match(new RegExp(`^${name}=(.*)$`, "m"))?.[1] || void 0;
|
|
110
|
+
}
|
|
111
|
+
async function handler() {
|
|
112
|
+
const cedarPaths = getPaths();
|
|
113
|
+
const shape = checkProjectShape(cedarPaths);
|
|
114
|
+
if (!shape.ok) {
|
|
115
|
+
if (shape.alreadyConverted) {
|
|
116
|
+
console.log(colors.note(shape.message));
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
console.error(colors.error(shape.message));
|
|
120
|
+
process.exit(1);
|
|
121
|
+
}
|
|
122
|
+
const envPath = path.join(cedarPaths.base, ".env");
|
|
123
|
+
const envContent = fs.existsSync(envPath) ? fs.readFileSync(envPath, "utf-8") : "";
|
|
124
|
+
const databaseUrl = readEnvVar(envContent, "DATABASE_URL");
|
|
125
|
+
const tasks = new Listr(
|
|
126
|
+
[
|
|
127
|
+
...getSqliteToPostgresTasks({ dbPath: shape.dbPath }),
|
|
128
|
+
installPackages,
|
|
129
|
+
{
|
|
130
|
+
title: "Running Prisma migrations",
|
|
131
|
+
skip: () => {
|
|
132
|
+
if (!databaseUrl) {
|
|
133
|
+
return `No DATABASE_URL found in \`.env\`. Set it to your PostgreSQL connection string, then run \`${prettyPrintCedarCommand(["prisma", "migrate", "dev"])}\``;
|
|
134
|
+
}
|
|
135
|
+
return false;
|
|
136
|
+
},
|
|
137
|
+
task: () => {
|
|
138
|
+
const result = execa.commandSync(
|
|
139
|
+
"yarn cedar prisma migrate dev --name init-postgres",
|
|
140
|
+
{
|
|
141
|
+
cwd: cedarPaths.base,
|
|
142
|
+
stdio: ["inherit", "inherit", "pipe"],
|
|
143
|
+
reject: false
|
|
144
|
+
}
|
|
145
|
+
);
|
|
146
|
+
if (result.exitCode !== 0) {
|
|
147
|
+
throw new Error(
|
|
148
|
+
"Prisma migration failed:\n\n" + result.stderr + `
|
|
149
|
+
|
|
150
|
+
You can try running it manually:
|
|
151
|
+
${prettyPrintCedarCommand(["prisma", "migrate", "dev", "--name", "init-postgres"])}`
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
],
|
|
157
|
+
{
|
|
158
|
+
exitOnError: false,
|
|
159
|
+
collectErrors: "minimal"
|
|
160
|
+
}
|
|
161
|
+
);
|
|
162
|
+
try {
|
|
163
|
+
await tasks.run();
|
|
164
|
+
if (tasks.errors.length > 0) {
|
|
165
|
+
for (const error of tasks.errors) {
|
|
166
|
+
if (isErrorWithMessage(error)) {
|
|
167
|
+
errorTelemetry(process.argv, error.message);
|
|
168
|
+
console.error(colors.error(error.message));
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
process.exit(1);
|
|
172
|
+
}
|
|
173
|
+
} catch (e) {
|
|
174
|
+
if (isErrorWithMessage(e)) {
|
|
175
|
+
errorTelemetry(process.argv, e.message);
|
|
176
|
+
console.error(colors.error(e.message));
|
|
177
|
+
}
|
|
178
|
+
if (isErrorWithExitCode(e)) {
|
|
179
|
+
process.exit(e.exitCode);
|
|
180
|
+
}
|
|
181
|
+
process.exit(1);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
function isErrorWithMessage(e) {
|
|
185
|
+
return !!e && typeof e === "object" && "message" in e;
|
|
186
|
+
}
|
|
187
|
+
function isErrorWithExitCode(e) {
|
|
188
|
+
return !!e && typeof e === "object" && "exitCode" in e && typeof e.exitCode === "number";
|
|
189
|
+
}
|
|
190
|
+
export {
|
|
191
|
+
checkProjectShape,
|
|
192
|
+
getSqliteToPostgresTasks,
|
|
193
|
+
handler
|
|
194
|
+
};
|
|
@@ -4,7 +4,6 @@ import * as parser from "@babel/parser";
|
|
|
4
4
|
import * as t from "@babel/types";
|
|
5
5
|
import execa from "execa";
|
|
6
6
|
import { Listr } from "listr2";
|
|
7
|
-
import * as recast from "recast";
|
|
8
7
|
import { getConfigPath, getConfig } from "@cedarjs/project-config";
|
|
9
8
|
import { getPaths, writeFilesTask } from "../../../../lib/index.js";
|
|
10
9
|
const updateApiURLTask = (apiUrl) => {
|
|
@@ -88,14 +87,6 @@ const verifyUDSetupTask = () => {
|
|
|
88
87
|
}
|
|
89
88
|
};
|
|
90
89
|
};
|
|
91
|
-
function posToIndex(str, line, column) {
|
|
92
|
-
const lines = str.split("\n");
|
|
93
|
-
let index = 0;
|
|
94
|
-
for (let i = 0; i < line - 1; i++) {
|
|
95
|
-
index += lines[i].length + 1;
|
|
96
|
-
}
|
|
97
|
-
return index + column;
|
|
98
|
-
}
|
|
99
90
|
function resolveConfigObject(arg) {
|
|
100
91
|
if (t.isObjectExpression(arg)) {
|
|
101
92
|
return arg;
|
|
@@ -127,15 +118,9 @@ function insertPluginsBeforeCedar({
|
|
|
127
118
|
content,
|
|
128
119
|
pluginCodes
|
|
129
120
|
}) {
|
|
130
|
-
const ast =
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
return parser.parse(source, {
|
|
134
|
-
sourceType: "module",
|
|
135
|
-
plugins: ["typescript", "jsx"]
|
|
136
|
-
});
|
|
137
|
-
}
|
|
138
|
-
}
|
|
121
|
+
const ast = parser.parse(content, {
|
|
122
|
+
sourceType: "module",
|
|
123
|
+
plugins: ["typescript", "jsx"]
|
|
139
124
|
});
|
|
140
125
|
const defaultExport = ast.program.body.find(t.isExportDefaultDeclaration);
|
|
141
126
|
if (!defaultExport) {
|
|
@@ -163,33 +148,18 @@ function insertPluginsBeforeCedar({
|
|
|
163
148
|
return null;
|
|
164
149
|
}
|
|
165
150
|
const cedarNode = cedarElement;
|
|
166
|
-
if (!cedarNode.loc || !arrayExpr.loc || !pluginsProp.loc) {
|
|
151
|
+
if (!cedarNode.loc || !arrayExpr.loc || !pluginsProp.loc || cedarNode.start == null || arrayExpr.start == null || arrayExpr.end == null) {
|
|
167
152
|
return null;
|
|
168
153
|
}
|
|
169
154
|
const isInline = cedarNode.loc.start.line === arrayExpr.loc.start.line;
|
|
170
155
|
if (isInline) {
|
|
171
|
-
const
|
|
172
|
-
|
|
173
|
-
arrayExpr.loc.start.line,
|
|
174
|
-
arrayExpr.loc.start.column
|
|
175
|
-
);
|
|
176
|
-
const endPos = posToIndex(
|
|
177
|
-
content,
|
|
178
|
-
arrayExpr.loc.end.line,
|
|
179
|
-
arrayExpr.loc.end.column
|
|
180
|
-
);
|
|
181
|
-
const precedingText = content.slice(0, startPos);
|
|
182
|
-
const followingText = content.slice(endPos);
|
|
156
|
+
const precedingText = content.slice(0, arrayExpr.start);
|
|
157
|
+
const followingText = content.slice(arrayExpr.end);
|
|
183
158
|
const existingCodes = elements.flatMap((el) => {
|
|
184
|
-
if (
|
|
159
|
+
if (el?.start == null || el.end == null) {
|
|
185
160
|
return [];
|
|
186
161
|
}
|
|
187
|
-
return [
|
|
188
|
-
content.slice(
|
|
189
|
-
posToIndex(content, el.loc.start.line, el.loc.start.column),
|
|
190
|
-
posToIndex(content, el.loc.end.line, el.loc.end.column)
|
|
191
|
-
)
|
|
192
|
-
];
|
|
162
|
+
return [content.slice(el.start, el.end)];
|
|
193
163
|
});
|
|
194
164
|
const lines2 = content.split("\n");
|
|
195
165
|
const pluginsLine = pluginsProp.loc.start.line;
|
|
@@ -205,7 +175,7 @@ function insertPluginsBeforeCedar({
|
|
|
205
175
|
return precedingText + multiline + followingText;
|
|
206
176
|
}
|
|
207
177
|
const cedarLine = cedarNode.loc.start.line;
|
|
208
|
-
const insertPos =
|
|
178
|
+
const insertPos = cedarNode.start - cedarNode.loc.start.column;
|
|
209
179
|
const lines = content.split("\n");
|
|
210
180
|
const indent = (lines[cedarLine - 1].match(/^\s*/) ?? [""])[0];
|
|
211
181
|
const insertion = pluginCodes.map((code) => `${indent}${code},
|
|
@@ -16,6 +16,10 @@ import {
|
|
|
16
16
|
mysqlDatabaseService
|
|
17
17
|
} from "../templates/flightcontrol.js";
|
|
18
18
|
const { getConfig } = prismaInternals;
|
|
19
|
+
const APOLLO_PROVIDER_COMPONENT_NAMES = [
|
|
20
|
+
"CedarApolloProvider",
|
|
21
|
+
"RedwoodApolloProvider"
|
|
22
|
+
];
|
|
19
23
|
const getFlightcontrolJson = async (database) => {
|
|
20
24
|
const flightcontrolConfig = getFlightcontrolConfig();
|
|
21
25
|
if (database === "none") {
|
|
@@ -205,18 +209,26 @@ const updateApp = () => {
|
|
|
205
209
|
appContent[authLineIndex] = ` <AuthProvider type="dbAuth" config={{ fetchConfig: { credentials: 'include' } }}>
|
|
206
210
|
`;
|
|
207
211
|
}
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
)
|
|
212
|
+
let gqlLineIndex = -1;
|
|
213
|
+
let apolloProviderComponentName = "";
|
|
214
|
+
for (const componentName of APOLLO_PROVIDER_COMPONENT_NAMES) {
|
|
215
|
+
gqlLineIndex = appContent.findIndex(
|
|
216
|
+
(line) => line.includes(`<${componentName}`)
|
|
217
|
+
);
|
|
218
|
+
if (gqlLineIndex !== -1) {
|
|
219
|
+
apolloProviderComponentName = componentName;
|
|
220
|
+
break;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
211
223
|
if (gqlLineIndex === -1) {
|
|
212
224
|
console.log(`
|
|
213
|
-
Couldn't find <
|
|
225
|
+
Couldn't find <CedarApolloProvider in web/src/App.js
|
|
214
226
|
If (and when) you use *dbAuth*, you'll have to add the following fetch config manually:
|
|
215
227
|
|
|
216
228
|
graphQLClientConfig={{ httpLinkConfig: { credentials: 'include' }}}
|
|
217
229
|
`);
|
|
218
230
|
} else if (appContent.toString().match(/dbAuth/)) {
|
|
219
|
-
appContent[gqlLineIndex] = `
|
|
231
|
+
appContent[gqlLineIndex] = ` <${apolloProviderComponentName} graphQLClientConfig={{ httpLinkConfig: { credentials: 'include' }}} >
|
|
220
232
|
`;
|
|
221
233
|
}
|
|
222
234
|
fs.writeFileSync(appPath, appContent.join(EOL));
|
|
@@ -5,13 +5,7 @@ import { recordTelemetryAttributes, colors as c } from "@cedarjs/cli-helpers";
|
|
|
5
5
|
import { getPaths, getPrismaSchemas } from "@cedarjs/project-config";
|
|
6
6
|
import { errorTelemetry } from "@cedarjs/telemetry";
|
|
7
7
|
import { writeFilesTask, printSetupNotes } from "../../../../lib/index.js";
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
POSTGRES_YAML,
|
|
11
|
-
RENDER_HEALTH_CHECK,
|
|
12
|
-
RENDER_YAML,
|
|
13
|
-
SQLITE_YAML
|
|
14
|
-
} from "../templates/render.js";
|
|
8
|
+
import { POSTGRES_YAML, RENDER_YAML, SQLITE_YAML } from "../templates/render.js";
|
|
15
9
|
const { getConfig } = prismaInternals;
|
|
16
10
|
const getRenderYamlContent = async (database) => {
|
|
17
11
|
if (database === "none") {
|
|
@@ -54,14 +48,9 @@ const getRenderYamlContent = async (database) => {
|
|
|
54
48
|
const notes = [
|
|
55
49
|
"You are ready to deploy to Render!\n",
|
|
56
50
|
"Go to https://dashboard.render.com/iacs to create your account and deploy to Render",
|
|
57
|
-
"Check out the deployment docs at https://
|
|
58
|
-
"Note: After first deployment to Render update the rewrite rule destination in `./render.yaml`"
|
|
59
|
-
|
|
60
|
-
const additionalFiles = [
|
|
61
|
-
{
|
|
62
|
-
path: path.join(getPaths().base, "api/src/functions/healthz.js"),
|
|
63
|
-
content: RENDER_HEALTH_CHECK
|
|
64
|
-
}
|
|
51
|
+
"Check out the deployment docs at https://cedarjs.com/docs/deploy/render for detailed instructions",
|
|
52
|
+
"Note: After first deployment to Render update the rewrite rule destination in `./render.yaml`",
|
|
53
|
+
"Note: The api service now health checks `/graphql/health`. If a previous setup left an unused `api/src/functions/healthz.js` behind, you can delete it"
|
|
65
54
|
];
|
|
66
55
|
const handler = async ({
|
|
67
56
|
force,
|
|
@@ -83,11 +72,6 @@ const handler = async ({
|
|
|
83
72
|
return writeFilesTask(files, { overwriteExisting: force });
|
|
84
73
|
}
|
|
85
74
|
},
|
|
86
|
-
// Add health check api function
|
|
87
|
-
addFilesTask({
|
|
88
|
-
files: additionalFiles,
|
|
89
|
-
force
|
|
90
|
-
}),
|
|
91
75
|
printSetupNotes(notes)
|
|
92
76
|
],
|
|
93
77
|
{ rendererOptions: { collapseSubtasks: false } }
|
|
@@ -5,13 +5,15 @@ const PROJECT_NAME = path.basename(getPaths().base);
|
|
|
5
5
|
const RENDER_YAML = (database) => {
|
|
6
6
|
const apiUrl = getUserApiUrl().replace(/\/$/, "");
|
|
7
7
|
return `# Quick links to the docs:
|
|
8
|
-
# -
|
|
9
|
-
# - Render's
|
|
8
|
+
# - Deploying Cedar: https://cedarjs.com/docs/deploy/render
|
|
9
|
+
# - Render's own walkthrough (uses \`yarn rw\`, but just swap in \`yarn cedar\`):
|
|
10
|
+
# https://render.com/docs/deploy-redwood
|
|
11
|
+
# - Render's Blueprint spec: https://render.com/docs/blueprint-spec
|
|
10
12
|
|
|
11
13
|
services:
|
|
12
14
|
- name: ${PROJECT_NAME}-web
|
|
13
15
|
type: web
|
|
14
|
-
|
|
16
|
+
runtime: static
|
|
15
17
|
buildCommand: npm install --global corepack && yarn install && yarn cedar deploy render web
|
|
16
18
|
staticPublishPath: ./web/dist
|
|
17
19
|
|
|
@@ -22,11 +24,16 @@ services:
|
|
|
22
24
|
routes:
|
|
23
25
|
- type: rewrite
|
|
24
26
|
source: ${apiUrl}/*
|
|
25
|
-
# Replace \`destination\`
|
|
27
|
+
# Replace \`destination\` after your first deploy, with the api service's
|
|
28
|
+
# URL from the Render dashboard:
|
|
26
29
|
#
|
|
27
30
|
# \`\`\`
|
|
28
|
-
# destination: https
|
|
31
|
+
# destination: https://${PROJECT_NAME}-api.onrender.com/*
|
|
29
32
|
# \`\`\`
|
|
33
|
+
#
|
|
34
|
+
# This can't be filled in automatically \u2014 Render's \`fromService\` only
|
|
35
|
+
# resolves service hosts into \`envVars\`, not into a static site's route
|
|
36
|
+
# destination.
|
|
30
37
|
destination: replace_with_api_url/*
|
|
31
38
|
- type: rewrite
|
|
32
39
|
source: /*
|
|
@@ -35,11 +42,22 @@ services:
|
|
|
35
42
|
- name: ${PROJECT_NAME}-api
|
|
36
43
|
type: web
|
|
37
44
|
plan: free
|
|
38
|
-
|
|
45
|
+
runtime: node
|
|
39
46
|
region: oregon
|
|
40
47
|
buildCommand: npm install --global corepack && yarn install && yarn cedar build api
|
|
41
48
|
startCommand: yarn cedar deploy render api
|
|
42
49
|
|
|
50
|
+
# Proves the GraphQL server is actually serving, not just that the process
|
|
51
|
+
# is alive. Returns 200 with an \`x-yoga-id\` response header.
|
|
52
|
+
#
|
|
53
|
+
# The route is \`<apiRootPath><graphiQLEndpoint>/health\`, and the value below
|
|
54
|
+
# assumes both defaults (\`/\` and \`/graphql\`). Update it to match if you
|
|
55
|
+
# customize either \u2014 by setting \`CEDAR_API_ROOT_PATH\` in the envVars below,
|
|
56
|
+
# by passing \`apiRootPath\` to \`createServer\` in \`api/src/server.ts\`, or by
|
|
57
|
+
# setting \`graphiQLEndpoint\` in \`api/src/functions/graphql.ts\`. A mismatch
|
|
58
|
+
# here 404s, and Render will not promote the deploy.
|
|
59
|
+
healthCheckPath: /graphql/health
|
|
60
|
+
|
|
43
61
|
envVars:
|
|
44
62
|
${database}
|
|
45
63
|
`;
|
|
@@ -58,17 +76,9 @@ const SQLITE_YAML = ` - key: DATABASE_URL
|
|
|
58
76
|
name: sqlite-data
|
|
59
77
|
mountPath: /opt/render/project/src/api/db/data
|
|
60
78
|
sizeGB: 1`;
|
|
61
|
-
const RENDER_HEALTH_CHECK = `// render-health-check
|
|
62
|
-
export const handler = async () => {
|
|
63
|
-
return {
|
|
64
|
-
statusCode: 200,
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
`;
|
|
68
79
|
export {
|
|
69
80
|
POSTGRES_YAML,
|
|
70
81
|
PROJECT_NAME,
|
|
71
|
-
RENDER_HEALTH_CHECK,
|
|
72
82
|
RENDER_YAML,
|
|
73
83
|
SQLITE_YAML
|
|
74
84
|
};
|
|
@@ -94,11 +94,8 @@ ENV NODE_ENV=production
|
|
|
94
94
|
|
|
95
95
|
# default api serve command
|
|
96
96
|
# ---------
|
|
97
|
-
#
|
|
98
|
-
#
|
|
99
|
-
# This is important if you intend to configure GraphQL to use Realtime.
|
|
100
|
-
#
|
|
101
|
-
# CMD [ "./api/dist/server.js" ]
|
|
97
|
+
# See https://cedarjs.com/docs/server-file for customizing the api server
|
|
98
|
+
# (Realtime, custom Fastify plugins, etc).
|
|
102
99
|
CMD ["node_modules/.bin/cedarjs-server", "api"]
|
|
103
100
|
|
|
104
101
|
# web serve
|
|
@@ -4,11 +4,8 @@ services:
|
|
|
4
4
|
context: .
|
|
5
5
|
dockerfile: ./Dockerfile
|
|
6
6
|
target: api_serve
|
|
7
|
-
#
|
|
8
|
-
#
|
|
9
|
-
# command to launch your server or update the Dockerfile to do so.
|
|
10
|
-
# This is important if you intend to configure GraphQL to use Realtime.
|
|
11
|
-
# command: "./api/dist/server.js"
|
|
7
|
+
# See https://cedarjs.com/docs/server-file for customizing the api
|
|
8
|
+
# server (Realtime, custom Fastify plugins, etc).
|
|
12
9
|
ports:
|
|
13
10
|
- '8911:8911'
|
|
14
11
|
depends_on:
|
|
@@ -16,8 +16,11 @@ function isPropertyWithName(node, name) {
|
|
|
16
16
|
function transform(file, api) {
|
|
17
17
|
const j = api.jscodeshift;
|
|
18
18
|
const root = j(file.source);
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
let apolloProviderElements = root.findJSXElements("CedarApolloProvider");
|
|
20
|
+
if (apolloProviderElements.length === 0) {
|
|
21
|
+
apolloProviderElements = root.findJSXElements("RedwoodApolloProvider");
|
|
22
|
+
}
|
|
23
|
+
const graphQLClientConfigCollection = apolloProviderElements.find(
|
|
21
24
|
j.JSXAttribute,
|
|
22
25
|
{
|
|
23
26
|
name: { name: "graphQLClientConfig" }
|
|
@@ -104,7 +107,7 @@ function transform(file, api) {
|
|
|
104
107
|
cacheConfigValue.properties.push(property);
|
|
105
108
|
}
|
|
106
109
|
graphQLClientConfigCollection.remove();
|
|
107
|
-
|
|
110
|
+
apolloProviderElements.get(0).node.openingElement.attributes.push(
|
|
108
111
|
j.jsxAttribute(
|
|
109
112
|
j.jsxIdentifier("graphQLClientConfig"),
|
|
110
113
|
j.jsxExpressionContainer(j.identifier(graphQLClientConfigVariableName))
|