Skip to content

Commit

Permalink
Updates to convex-js
Browse files Browse the repository at this point in the history
GitOrigin-RevId: a01f1374c4a844b3c8b60fe2254c5ead2712d99f
  • Loading branch information
Convex, Inc authored and thomasballinger committed Nov 21, 2023
1 parent cb41d1e commit 32ff1dc
Show file tree
Hide file tree
Showing 31 changed files with 419 additions and 174 deletions.
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,20 @@

## Upcoming

## 1.5.0

- Preview deployments

## 1.4.0

- External packages in Node.js
- `npx convex run` now does not push code, `npx convex run --push` instead

## 1.3.0

- `ConvexClient` callback-based WebSocket client
- `ConvexError`
- `npx convex dev --tail-logs`

## 1.2.0

Expand Down
4 changes: 2 additions & 2 deletions bin/main-dev
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
#!/bin/bash
SCRIPTDIR="$(echo "$0" | python3 -c 'import os; print(os.path.dirname(os.path.realpath(input())))')"
"exec" "$SCRIPTDIR/../node_modules/.bin/ts-node-esm" "--swc" "$SCRIPTDIR/../src/cli/index.ts" "$@"
CONVEXDIR="$(dirname "$(dirname "$0")")"
"exec" "$CONVEXDIR/node_modules/.bin/ts-node-esm" "--swc" "$CONVEXDIR/src/cli/index.ts" "$@"
3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "convex",
"description": "Client for the Convex Cloud",
"version": "1.5.1",
"version": "1.6.2",
"author": "Convex, Inc. <[email protected]>",
"homepage": "https://convex.dev",
"main": "./dist/cjs/index.js",
Expand Down Expand Up @@ -135,7 +135,6 @@
"format": "prettier -w . && eslint --fix .",
"format-check": "prettier -c . && eslint . --ext .js,.jsx,.ts,.tsx",
"prepare": "npm run build",
"prepublishOnly": "echo \"publish command should not be used directly, instead pack first then publish the .tgz file.\"; false",
"prepack": "node scripts/prepack.mjs",
"postpack": "node scripts/postpack.mjs",
"test": "NODE_OPTIONS=--experimental-vm-modules jest",
Expand Down
8 changes: 8 additions & 0 deletions src/bundler/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,14 @@ export async function bundleSchema(ctx: Context, dir: string) {

export async function bundleAuthConfig(ctx: Context, dir: string) {
const authConfigPath = path.resolve(dir, "auth.config.js");
const authConfigTsPath = path.resolve(dir, "auth.config.ts");
if (!ctx.fs.exists(authConfigPath) && ctx.fs.exists(authConfigTsPath)) {
logFailure(
ctx,
`Auth config file ${authConfigTsPath} found with .ts extension, but auth.config.js must be a JavaScript file.`
);
return await ctx.crash(1, "invalid filesystem data");
}
if (!ctx.fs.exists(authConfigPath)) {
return [];
}
Expand Down
2 changes: 1 addition & 1 deletion src/cli/codegen_templates/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export function apiCodegen(modulePaths: string[]): GeneratedJsWithTypes {
(modulePath) =>
`import type * as ${moduleIdentifier(modulePath)} from "../${importPath(
modulePath
)}";`
)}.js";`
)
.join("\n")}
Expand Down
9 changes: 3 additions & 6 deletions src/cli/codegen_templates/dataModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,9 @@ import { GeneratedJsWithTypes, header } from "./common.js";

const dataModelDTS = `
${header("Generated data model types.")}
import type {
DataModelFromSchemaDefinition,
} from "convex/server";
import type { DocumentByName, TableNamesInDataModel } from "convex/server";
import type { DataModelFromSchemaDefinition, DocumentByName, TableNamesInDataModel, SystemTableNames } from "convex/server";
import type { GenericId } from "convex/values";
import schema from "../schema";
import schema from "../schema.js";
/**
* The names of all of your Convex tables.
Expand All @@ -34,7 +31,7 @@ const dataModelDTS = `
*
* @typeParam TableName - A string literal type of the table name (like "users").
*/
export type Id<TableName extends TableNames> = GenericId<TableName>;
export type Id<TableName extends TableNames | SystemTableNames> = GenericId<TableName>;
/**
* A type describing your Convex data model.
Expand Down
3 changes: 2 additions & 1 deletion src/cli/convexImport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ async function determineFormat(
csv: ".csv",
jsonLines: ".jsonl",
jsonArray: ".json",
zip: ".zip",
};
const extensionToFormat = Object.fromEntries(
Object.entries(formatToExtension).map((a) => a.reverse())
Expand All @@ -130,7 +131,7 @@ async function determineFormat(
)
);
}
format ??= extensionToFormat[fileExtension];
format ??= extensionToFormat[fileExtension] ?? null;
}
if (format === null) {
logFailure(
Expand Down
2 changes: 2 additions & 0 deletions src/cli/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { reinit } from "./reinit.js";
import { update } from "./update.js";
import { typecheck } from "./typecheck.js";
import { login } from "./login.js";
import { logout } from "./logout.js";
import chalk from "chalk";
import * as Sentry from "@sentry/node";
import "@sentry/tracing";
Expand Down Expand Up @@ -100,6 +101,7 @@ async function main() {
.addCommand(docs)
.addCommand(update)
.addCommand(logs)
.addCommand(logout)
.addHelpCommand("help <command>", "Show help for given <command>")
.version(version)
// Hide version and help so they don't clutter
Expand Down
34 changes: 8 additions & 26 deletions src/cli/lib/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import {
logAndHandleAxiosError,
ErrorData,
deploymentClient,
loadPackageJson,
} from "./utils.js";
export { productionProvisionHost, provisionHost } from "./utils.js";

Expand Down Expand Up @@ -142,10 +143,6 @@ export async function parseProjectConfig(
}
}

// Important! We return the object itself (not a new object) because
// we want to ensure that fields we're unaware of are "passed through".
// It's possible that this is an old client and the server knows about new
// fields that we don't.
return obj;
}

Expand Down Expand Up @@ -221,36 +218,21 @@ export async function getFunctionsDirectoryPath(ctx: Context): Promise<string> {
return functionsDir(configPath, projectConfig);
}

/** Merge configurations between a ProjectConfig and the local `convex.json` file.
* If local config contains a more privileged project configuration value that
* is not populated by /api/get_config, this method will select the more
* privileged value.
* */
export async function mergeWithLocalConfig(
ctx: Context,
remoteConfig: ProjectConfig
): Promise<ProjectConfig> {
const newConfig = { ...remoteConfig };
const { projectConfig: localConfig } = await readProjectConfig(ctx);

if (newConfig.generateCommonJSApi === false) {
newConfig.generateCommonJSApi = localConfig.generateCommonJSApi;
}
if (newConfig.node.externalPackages.length === 0) {
newConfig.node.externalPackages = localConfig.node.externalPackages;
}
return newConfig;
}

/** Read configuration from a local `convex.json` file. */
export async function readProjectConfig(ctx: Context): Promise<{
projectConfig: ProjectConfig;
configPath: string;
}> {
if (!ctx.fs.exists("convex.json")) {
// create-react-app bans imports from outside of src, so we can just
// put the functions directory inside of src/ to work around this issue.
const packages = await loadPackageJson(ctx);
const isCreateReactApp = "react-scripts" in packages;
return {
projectConfig: {
functions: DEFAULT_FUNCTIONS_PATH,
functions: isCreateReactApp
? `src/${DEFAULT_FUNCTIONS_PATH}`
: DEFAULT_FUNCTIONS_PATH,
node: {
externalPackages: [],
},
Expand Down
40 changes: 7 additions & 33 deletions src/cli/lib/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,14 @@ import { doCodegen, doInitCodegen } from "./codegen.js";
import {
configFilepath,
getFunctionsDirectoryPath,
pullConfig,
readProjectConfig,
upgradeOldAuthInfoToAuthConfig,
writeProjectConfig,
} from "./config.js";
import { writeDeploymentEnvVar } from "./deployment.js";
import { writeConvexUrlToEnvFile } from "./envvars.js";
import {
functionsDir,
loadPackageJson,
logAndHandleAxiosError,
validateOrSelectTeam,
} from "./utils.js";
Expand Down Expand Up @@ -59,14 +58,7 @@ export async function init(

showSpinner(ctx, "Creating new Convex project...");

let projectSlug,
teamSlug,
deploymentName,
url,
adminKey,
projectsRemaining,
projectConfig,
modules;
let projectSlug, teamSlug, deploymentName, url, adminKey, projectsRemaining;
try {
({
projectSlug,
Expand All @@ -80,14 +72,6 @@ export async function init(
{ teamSlug: selectedTeam, projectName },
deploymentType
));

({ projectConfig, modules } = await pullConfig(
ctx,
projectSlug,
teamSlug,
url,
adminKey
));
} catch (err) {
logFailure(ctx, "Unable to create project.");
return await logAndHandleAxiosError(ctx, err);
Expand Down Expand Up @@ -116,19 +100,9 @@ export async function init(
);
}

if (modules.length > 0) {
logFailure(ctx, chalk.red("Error: Unexpected modules in new project"));
return await ctx.crash(1, undefined);
}
const { projectConfig: existingProjectConfig } = await readProjectConfig(ctx);

// create-react-app bans imports from outside of src, so we can just
// put the functions directory inside of src/ to work around this issue.
const packages = await loadPackageJson(ctx);
const isCreateReactApp = "react-scripts" in packages;
if (isCreateReactApp) {
projectConfig.functions = `src/${projectConfig.functions}`;
}
const functionsPath = functionsDir(configPath, projectConfig);
const functionsPath = functionsDir(configPath, existingProjectConfig);

const { wroteToGitIgnore } = await writeDeploymentEnvVar(
ctx,
Expand All @@ -140,12 +114,12 @@ export async function init(
}
);

const projectConfigWithoutAuthInfo = await upgradeOldAuthInfoToAuthConfig(
const projectConfig = await upgradeOldAuthInfoToAuthConfig(
ctx,
projectConfig,
existingProjectConfig,
functionsPath
);
await writeProjectConfig(ctx, projectConfigWithoutAuthInfo);
await writeProjectConfig(ctx, projectConfig);

await doInitCodegen({
ctx,
Expand Down
8 changes: 6 additions & 2 deletions src/cli/lib/login.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ import { execSync } from "child_process";
import os from "os";

const SCOPE = "openid email profile";
/// This value was created long ago, and cannot be changed easily.
/// It's just a fixed string used for identifying the Auth0 token, so it's fine
/// and not user-facing.
const AUDIENCE = "https://console.convex.dev/api/";

// Per https://github.com/panva/node-openid-client/tree/main/docs#customizing
custom.setHttpOptionsDefaults({
Expand Down Expand Up @@ -137,7 +141,7 @@ async function performDeviceAuthorization(
try {
handle = await auth0Client.deviceAuthorization({
scope: SCOPE,
audience: "https://console.convex.dev/api/",
audience: AUDIENCE,
});
} catch (error) {
// We couldn't get verification URL from Auth0, proceed with manual auth
Expand Down Expand Up @@ -250,7 +254,7 @@ async function performPasswordAuthentication(
password: password,
scope: SCOPE,
client_id: clientId,
audience: "https://console.convex.dev/api/",
audience: AUDIENCE,
// Note that there is no client secret provided, as Auth0 refuses to require it for untrusted apps.
}),
};
Expand Down
30 changes: 10 additions & 20 deletions src/cli/lib/reinit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ import {
import { doCodegen } from "./codegen.js";
import {
configName,
mergeWithLocalConfig,
pullConfig,
readProjectConfig,
upgradeOldAuthInfoToAuthConfig,
writeProjectConfig,
Expand Down Expand Up @@ -38,7 +36,8 @@ export async function reinit(
"Project:"
);
if (!projectSlug) {
logFailure(ctx, "Aborted");
logFailure(ctx, "Run the command again to create a new project instead.");
await ctx.crash(1);
return;
}

Expand All @@ -50,18 +49,11 @@ export async function reinit(
{ teamSlug, projectSlug },
deploymentType
);
const { projectConfig: projectConfigFromBackend } = await pullConfig(
ctx,
projectSlug,
teamSlug,
url,
adminKey
);
// Merge remote config with local config
const mergedProjectConfig = await mergeWithLocalConfig(
ctx,
projectConfigFromBackend
);

const { configPath, projectConfig: existingProjectConfig } =
await readProjectConfig(ctx);

const functionsPath = functionsDir(configName(), existingProjectConfig);

const { wroteToGitIgnore } = await writeDeploymentEnvVar(
ctx,
Expand All @@ -73,17 +65,15 @@ export async function reinit(
}
);

const functionsPath = functionsDir(configName(), projectConfigFromBackend);
const projectConfigWithoutAuthInfo = await upgradeOldAuthInfoToAuthConfig(
const projectConfig = await upgradeOldAuthInfoToAuthConfig(
ctx,
mergedProjectConfig,
existingProjectConfig,
functionsPath
);
await writeProjectConfig(ctx, projectConfigWithoutAuthInfo, {
await writeProjectConfig(ctx, projectConfig, {
deleteIfAllDefault: true,
});

const { projectConfig, configPath } = await readProjectConfig(ctx);
await doCodegen({
ctx,
functionsDirectoryPath: functionsDir(configPath, projectConfig),
Expand Down
Loading

0 comments on commit 32ff1dc

Please sign in to comment.