convex
Version:
Client for the Convex Cloud
249 lines (248 loc) • 8.06 kB
JavaScript
;
import path from "path";
import { changeSpinner, logMessage } from "../../bundler/context.js";
import {
configFromProjectConfig,
getFunctionsDirectoryPath,
readProjectConfig
} from "./config.js";
import { finishPush, startPush, waitForSchema } from "./deploy2.js";
import { version } from "../version.js";
import { runNonComponentsPush } from "./push.js";
import { ensureHasConvexDependency, functionsDir } from "./utils/utils.js";
import {
bundleDefinitions,
bundleImplementations,
componentGraph
} from "./components/definition/bundle.js";
import { isComponentDirectory } from "./components/definition/directoryStructure.js";
import {
doFinalComponentCodegen,
doInitialComponentCodegen,
doInitCodegen,
doCodegen
} from "./codegen.js";
import { typeCheckFunctionsInMode } from "./typecheck.js";
import { withTmpDir } from "../../bundler/fs.js";
import { ROOT_DEFINITION_FILENAME } from "./components/constants.js";
import { handleDebugBundlePath } from "./debugBundlePath.js";
import chalk from "chalk";
import {
deploymentSelectionFromOptions,
fetchDeploymentCredentialsProvisionProd
} from "./api.js";
export async function runCodegen(ctx, options) {
await ensureHasConvexDependency(ctx, "codegen");
const { configPath, projectConfig } = await readProjectConfig(ctx);
const functionsDirectoryPath = functionsDir(configPath, projectConfig);
const componentRootPath = path.resolve(
path.join(functionsDirectoryPath, ROOT_DEFINITION_FILENAME)
);
if (ctx.fs.exists(componentRootPath)) {
const deploymentSelection = deploymentSelectionFromOptions(options);
const credentials = await fetchDeploymentCredentialsProvisionProd(
ctx,
deploymentSelection
);
await startComponentsPushAndCodegen(ctx, projectConfig, configPath, {
...options,
...credentials,
generateCommonJSApi: options.commonjs,
verbose: options.dryRun
});
} else {
if (options.init) {
await doInitCodegen(ctx, functionsDirectoryPath, false, {
dryRun: options.dryRun,
debug: options.debug
});
}
if (options.typecheck !== "disable") {
logMessage(ctx, chalk.gray("Running TypeScript typecheck\u2026"));
}
await doCodegen(ctx, functionsDirectoryPath, options.typecheck, {
dryRun: options.dryRun,
debug: options.debug,
generateCommonJSApi: options.commonjs
});
}
}
export async function runPush(ctx, options) {
const { configPath, projectConfig } = await readProjectConfig(ctx);
const convexDir = functionsDir(configPath, projectConfig);
const componentRootPath = path.resolve(
path.join(convexDir, ROOT_DEFINITION_FILENAME)
);
if (ctx.fs.exists(componentRootPath)) {
await runComponentsPush(ctx, options, configPath, projectConfig);
} else {
await runNonComponentsPush(ctx, options, configPath, projectConfig);
}
}
async function startComponentsPushAndCodegen(ctx, projectConfig, configPath, options) {
const verbose = options.verbose || options.dryRun;
const convexDir = await getFunctionsDirectoryPath(ctx);
const absWorkingDir = path.resolve(".");
const isComponent = isComponentDirectory(ctx, convexDir, true);
if (isComponent.kind === "err") {
return await ctx.crash({
exitCode: 1,
errorType: "invalid filesystem data",
printedMessage: `Invalid component root directory (${isComponent.why}): ${convexDir}`
});
}
const rootComponent = isComponent.component;
changeSpinner(ctx, "Traversing component definitions...");
const { components, dependencyGraph } = await componentGraph(
ctx,
absWorkingDir,
rootComponent,
verbose
);
changeSpinner(ctx, "Generating server code...");
await withTmpDir(async (tmpDir) => {
await doInitialComponentCodegen(ctx, tmpDir, rootComponent, options);
for (const directory of components.values()) {
await doInitialComponentCodegen(ctx, tmpDir, directory, options);
}
});
changeSpinner(ctx, "Bundling component definitions...");
const {
appDefinitionSpecWithoutImpls,
componentDefinitionSpecsWithoutImpls
} = await bundleDefinitions(
ctx,
absWorkingDir,
dependencyGraph,
rootComponent,
// Note that this *includes* the root component.
[...components.values()]
);
changeSpinner(ctx, "Bundling component schemas and implementations...");
const { appImplementation, componentImplementations } = await bundleImplementations(
ctx,
rootComponent,
[...components.values()],
projectConfig.node.externalPackages,
verbose
);
if (options.debugBundlePath) {
const { config: localConfig } = await configFromProjectConfig(
ctx,
projectConfig,
configPath,
verbose
);
await handleDebugBundlePath(ctx, options.debugBundlePath, localConfig);
logMessage(
ctx,
`Wrote bundle and metadata for modules in the root to ${options.debugBundlePath}. Skipping rest of push.`
);
return null;
}
const udfServerVersion = version;
const appDefinition = {
...appDefinitionSpecWithoutImpls,
...appImplementation,
udfServerVersion
};
const componentDefinitions = [];
for (const componentDefinition of componentDefinitionSpecsWithoutImpls) {
const impl = componentImplementations.filter(
(impl2) => impl2.definitionPath === componentDefinition.definitionPath
)[0];
if (!impl) {
return await ctx.crash({
exitCode: 1,
errorType: "fatal",
printedMessage: `missing! couldn't find ${componentDefinition.definitionPath} in ${componentImplementations.map((impl2) => impl2.definitionPath).toString()}`
});
}
componentDefinitions.push({
...componentDefinition,
...impl,
udfServerVersion
});
}
const startPushRequest = {
adminKey: options.adminKey,
dryRun: false,
functions: projectConfig.functions,
appDefinition,
componentDefinitions,
nodeDependencies: appImplementation.externalNodeDependencies
};
if (options.writePushRequest) {
const pushRequestPath = path.resolve(options.writePushRequest);
ctx.fs.writeUtf8File(
`${pushRequestPath}.json`,
JSON.stringify(startPushRequest)
);
return null;
}
const startPushResponse = await startPush(
ctx,
options.url,
startPushRequest,
verbose
);
verbose && console.log("startPush:");
verbose && console.dir(startPushResponse, { depth: null });
changeSpinner(ctx, "Finalizing code generation...");
await withTmpDir(async (tmpDir) => {
await doFinalComponentCodegen(
ctx,
tmpDir,
rootComponent,
rootComponent,
startPushResponse,
options
);
for (const directory of components.values()) {
await doFinalComponentCodegen(
ctx,
tmpDir,
rootComponent,
directory,
startPushResponse,
options
);
}
});
changeSpinner(ctx, "Running TypeScript...");
await typeCheckFunctionsInMode(ctx, options.typecheck, rootComponent.path);
for (const directory of components.values()) {
await typeCheckFunctionsInMode(ctx, options.typecheck, directory.path);
}
return startPushResponse;
}
export async function runComponentsPush(ctx, options, configPath, projectConfig) {
const verbose = options.verbose || options.dryRun;
await ensureHasConvexDependency(ctx, "push");
if (options.dryRun) {
return await ctx.crash({
exitCode: 1,
errorType: "fatal",
printedMessage: "dryRun not allowed yet"
});
}
const startPushResponse = await startComponentsPushAndCodegen(
ctx,
projectConfig,
configPath,
options
);
if (!startPushResponse) {
return;
}
changeSpinner(ctx, "Waiting for schema...");
await waitForSchema(ctx, options.adminKey, options.url, startPushResponse);
const finishPushResponse = await finishPush(
ctx,
options.adminKey,
options.url,
startPushResponse
);
verbose && console.log("finishPush:", finishPushResponse);
}
//# sourceMappingURL=components.js.map