convex 1.43.0 → 1.44.0
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/CHANGELOG.md +130 -113
- package/dist/browser.bundle.js +1 -1
- package/dist/browser.bundle.js.map +1 -1
- package/dist/cjs/cli/codegen_templates/component_server.js +4 -3
- package/dist/cjs/cli/codegen_templates/component_server.js.map +2 -2
- package/dist/cjs/cli/codegen_templates/server.js +24 -12
- package/dist/cjs/cli/codegen_templates/server.js.map +2 -2
- package/dist/cjs/cli/lib/login.js +12 -8
- package/dist/cjs/cli/lib/login.js.map +2 -2
- package/dist/cjs/cli/login.js +52 -7
- package/dist/cjs/cli/login.js.map +2 -2
- package/dist/cjs/index.js +1 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/react/ConvexAuthState.js +30 -32
- package/dist/cjs/react/ConvexAuthState.js.map +2 -2
- package/dist/cjs/server/impl/actions_impl.js +12 -0
- package/dist/cjs/server/impl/actions_impl.js.map +2 -2
- package/dist/cjs/server/index.js +3 -0
- package/dist/cjs/server/index.js.map +2 -2
- package/dist/cjs/server/schema.js +69 -1
- package/dist/cjs/server/schema.js.map +2 -2
- package/dist/cjs-types/cli/codegen_templates/component_server.d.ts.map +1 -1
- package/dist/cjs-types/cli/codegen_templates/server.d.ts +1 -0
- package/dist/cjs-types/cli/codegen_templates/server.d.ts.map +1 -1
- package/dist/cjs-types/cli/lib/login.d.ts +5 -0
- package/dist/cjs-types/cli/lib/login.d.ts.map +1 -1
- package/dist/cjs-types/cli/login.d.ts.map +1 -1
- package/dist/cjs-types/cli/login.test.d.ts +2 -0
- package/dist/cjs-types/cli/login.test.d.ts.map +1 -0
- package/dist/cjs-types/index.d.ts +1 -1
- package/dist/cjs-types/react/ConvexAuthState.d.ts.map +1 -1
- package/dist/cjs-types/server/impl/actions_impl.d.ts.map +1 -1
- package/dist/cjs-types/server/impl/actions_impl.test.d.ts +2 -0
- package/dist/cjs-types/server/impl/actions_impl.test.d.ts.map +1 -0
- package/dist/cjs-types/server/index.d.ts +2 -2
- package/dist/cjs-types/server/index.d.ts.map +1 -1
- package/dist/cjs-types/server/schema.d.ts +83 -5
- package/dist/cjs-types/server/schema.d.ts.map +1 -1
- package/dist/cli.bundle.cjs +1277 -570
- package/dist/cli.bundle.cjs.map +4 -4
- package/dist/esm/cli/codegen_templates/component_server.js +8 -4
- package/dist/esm/cli/codegen_templates/component_server.js.map +2 -2
- package/dist/esm/cli/codegen_templates/server.js +22 -11
- package/dist/esm/cli/codegen_templates/server.js.map +2 -2
- package/dist/esm/cli/lib/login.js +11 -8
- package/dist/esm/cli/lib/login.js.map +2 -2
- package/dist/esm/cli/login.js +54 -10
- package/dist/esm/cli/login.js.map +2 -2
- package/dist/esm/index.js +1 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/react/ConvexAuthState.js +31 -32
- package/dist/esm/react/ConvexAuthState.js.map +2 -2
- package/dist/esm/server/impl/actions_impl.js +11 -0
- package/dist/esm/server/impl/actions_impl.js.map +2 -2
- package/dist/esm/server/index.js +2 -1
- package/dist/esm/server/index.js.map +2 -2
- package/dist/esm/server/schema.js +67 -0
- package/dist/esm/server/schema.js.map +2 -2
- package/dist/esm-types/cli/codegen_templates/component_server.d.ts.map +1 -1
- package/dist/esm-types/cli/codegen_templates/server.d.ts +1 -0
- package/dist/esm-types/cli/codegen_templates/server.d.ts.map +1 -1
- package/dist/esm-types/cli/lib/login.d.ts +5 -0
- package/dist/esm-types/cli/lib/login.d.ts.map +1 -1
- package/dist/esm-types/cli/login.d.ts.map +1 -1
- package/dist/esm-types/cli/login.test.d.ts +2 -0
- package/dist/esm-types/cli/login.test.d.ts.map +1 -0
- package/dist/esm-types/index.d.ts +1 -1
- package/dist/esm-types/react/ConvexAuthState.d.ts.map +1 -1
- package/dist/esm-types/server/impl/actions_impl.d.ts.map +1 -1
- package/dist/esm-types/server/impl/actions_impl.test.d.ts +2 -0
- package/dist/esm-types/server/impl/actions_impl.test.d.ts.map +1 -0
- package/dist/esm-types/server/index.d.ts +2 -2
- package/dist/esm-types/server/index.d.ts.map +1 -1
- package/dist/esm-types/server/schema.d.ts +83 -5
- package/dist/esm-types/server/schema.d.ts.map +1 -1
- package/dist/react.bundle.js +31 -33
- package/dist/react.bundle.js.map +2 -2
- package/package.json +3 -4
- package/src/cli/codegen_templates/component_server.ts +12 -6
- package/src/cli/codegen_templates/server.ts +36 -19
- package/src/cli/lib/login.ts +20 -9
- package/src/cli/login.test.ts +261 -0
- package/src/cli/login.ts +88 -13
- package/src/index.ts +1 -1
- package/src/react/ConvexAuthState.tsx +15 -7
- package/src/server/impl/actions_impl.test.ts +59 -0
- package/src/server/impl/actions_impl.ts +23 -0
- package/src/server/index.ts +7 -1
- package/src/server/schema.test.ts +98 -0
- package/src/server/schema.ts +178 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/cli/login.ts"],
|
|
4
|
-
"sourcesContent": ["import { Command, Option } from \"@commander-js/extra-typings\";\nimport { Context, oneoffContext } from \"../bundler/context.js\";\nimport { logFinishedStep, logMessage } from \"../bundler/log.js\";\nimport { checkAuthorization, performLogin } from \"./lib/login.js\";\nimport {\n loadProjectLocalConfig,\n loadUuidForAnonymousUser,\n} from \"./lib/localDeployment/filePaths.js\";\nimport {\n handleLinkToProject,\n listLegacyAnonymousDeployments,\n} from \"./lib/localDeployment/anonymous.js\";\nimport {\n DASHBOARD_HOST,\n deploymentDashboardUrlPage,\n teamDashboardUrl,\n} from \"./lib/dashboard.js\";\nimport { promptSearch, promptYesNo } from \"./lib/utils/prompts.js\";\nimport { validateOrSelectTeam } from \"./lib/utils/utils.js\";\nimport {\n selectProject,\n updateEnvAndConfigForDeploymentSelection,\n} from \"./configure.js\";\nimport {\n getDeploymentSelection,\n shouldAllowAnonymousDevelopment,\n} from \"./lib/deploymentSelection.js\";\nimport {\n isAnonymousDeployment,\n removeAnonymousPrefix,\n} from \"./lib/deployment.js\";\nimport {\n readGlobalConfig,\n globalConfigPath,\n} from \"./lib/utils/globalConfig.js\";\nimport { getTeamsForUser } from \"./lib/api.js\";\n\nconst loginStatus = new Command(\"status\")\n .description(\"Check login status and list accessible teams\")\n .allowExcessArguments(false)\n .action(async () => {\n const ctx = await oneoffContext({\n url: undefined,\n adminKey: undefined,\n envFile: undefined,\n });\n\n const globalConfig = readGlobalConfig(ctx);\n const hasToken = globalConfig?.accessToken !== null;\n\n if (hasToken) {\n logMessage(`Convex account token found in: ${globalConfigPath()}`);\n } else {\n logMessage(\"No token found locally\");\n return;\n }\n\n const isLoggedIn = await checkAuthorization(ctx, false);\n\n if (!isLoggedIn) {\n logMessage(\"Status: Not logged in\");\n return;\n }\n\n logMessage(\"Status: Logged in\");\n const teams = await getTeamsForUser(ctx);\n logMessage(\n `Teams: ${teams.length} team${teams.length === 1 ? \"\" : \"s\"} accessible`,\n );\n for (const team of teams) {\n logMessage(` - ${team.name} (${team.slug})`);\n }\n });\n\nexport const login = new Command(\"login\")\n .description(\"Login to Convex\")\n .allowExcessArguments(false)\n .option(\n \"--device-name <name>\",\n \"Provide a name for the device being authorized\",\n )\n .option(\n \"-f, --force\",\n \"Proceed with login even if a valid access token already exists for this device\",\n )\n .option(\n \"--no-open\",\n \"Don't automatically open the login link in the default browser\",\n )\n .addOption(\n new Option(\n \"--login-flow <mode>\",\n `How to log in; defaults to guessing based on the environment.`,\n )\n .choices([\"paste\", \"auto\", \"poll\"] as const)\n .default(\"auto\" as const),\n )\n .addOption(new Option(\"--link-deployments\").hideHelp())\n // These options are hidden from the help/usage message, but allow overriding settings for testing.\n // Change the auth credentials with the auth provider\n .addOption(new Option(\"--override-auth-url <url>\").hideHelp())\n .addOption(new Option(\"--override-auth-client <id>\").hideHelp())\n .addOption(new Option(\"--override-auth-username <username>\").hideHelp())\n .addOption(new Option(\"--override-auth-password <password>\").hideHelp())\n // Skip the auth provider login and directly use this access token\n .addOption(new Option(\"--override-access-token <token>\").hideHelp())\n // Automatically accept opt ins without prompting\n .addOption(new Option(\"--accept-opt-ins\").hideHelp())\n // Dump the access token from the auth provider and skip authorization with Convex\n .addOption(new Option(\"--dump-access-token\").hideHelp())\n // Hidden option for tests to check if the user is logged in.\n .addOption(new Option(\"--check-login\").hideHelp())\n // Redirect to Vercel SSO integration URL\n .addOption(\n new Option(\n \"--vercel\",\n \"Redirect to Vercel SSO integration for login\",\n ).hideHelp(),\n )\n // Override the Vercel URL slug (defaults to 'convex')\n .addOption(new Option(\"--vercel-override <slug>\").hideHelp())\n .addCommand(loginStatus)\n .addHelpCommand(false)\n .action(async (options, cmd: Command) => {\n const ctx = await oneoffContext({\n url: undefined,\n adminKey: undefined,\n envFile: undefined,\n });\n if (\n !options.force &&\n (await checkAuthorization(ctx, !!options.acceptOptIns))\n ) {\n logFinishedStep(\n \"This device has previously been authorized and is ready for use with Convex.\",\n );\n await handleLinkingDeployments(ctx, {\n interactive: !!options.linkDeployments,\n });\n return;\n }\n if (!options.force && options.checkLogin) {\n const isLoggedIn = await checkAuthorization(ctx, !!options.acceptOptIns);\n if (!isLoggedIn) {\n return ctx.crash({\n exitCode: 1,\n errorType: \"fatal\",\n errForSentry: \"You are not logged in.\",\n printedMessage: \"You are not logged in.\",\n });\n }\n }\n if (!!options.overrideAuthUsername !== !!options.overrideAuthPassword) {\n cmd.error(\n \"If overriding credentials, both username and password must be provided\",\n );\n }\n\n const uuid = loadUuidForAnonymousUser(ctx);\n await performLogin(ctx, {\n ...options,\n anonymousId: uuid,\n vercel: options.vercel,\n vercelOverride: options.vercelOverride,\n });\n\n await handleLinkingDeployments(ctx, {\n interactive: !!options.linkDeployments,\n });\n });\n\nasync function handleLinkingDeployments(\n ctx: Context,\n args: {\n interactive: boolean;\n },\n) {\n if (!shouldAllowAnonymousDevelopment()) {\n return;\n }\n\n // Check for project-local anonymous deployment first - this takes priority\n const projectLocal = loadProjectLocalConfig(ctx);\n if (\n projectLocal !== null &&\n isAnonymousDeployment(projectLocal.deploymentName)\n ) {\n const shouldLink = await promptYesNo(ctx, {\n message: `Would you like to link your existing deployment to your account? (\"${projectLocal.deploymentName}\")`,\n default: true,\n });\n if (!shouldLink) {\n logMessage(\n \"Not linking your existing deployment. If you want to link it later, run `npx convex login --link-deployments`.\",\n );\n logMessage(\n `Visit ${DASHBOARD_HOST} or run \\`npx convex dev\\` to get started with your new account.`,\n );\n return;\n }\n\n const { dashboardUrl } = await linkSingleDeployment(\n ctx,\n projectLocal.deploymentName,\n projectLocal.deploymentName,\n );\n logFinishedStep(`Visit ${dashboardUrl} to get started.`);\n return;\n }\n\n // No project-local deployment - check for legacy deployments\n const legacyDeployments = listLegacyAnonymousDeployments(ctx);\n if (legacyDeployments.length === 0) {\n if (args.interactive) {\n logMessage(\n \"It doesn't look like you have any deployments to link. You can run `npx convex dev` to set up a new project or select an existing one.\",\n );\n }\n return;\n }\n\n // Get the currently configured deployment (if any) for env var updates\n const deploymentSelection = await getDeploymentSelection(ctx, {\n url: undefined,\n adminKey: undefined,\n envFile: undefined,\n });\n const configuredDeployment =\n deploymentSelection.kind === \"anonymous\"\n ? deploymentSelection.deploymentName\n : null;\n\n if (!args.interactive) {\n // Non-interactive: link all legacy deployments automatically\n const message = getMessage(legacyDeployments.map((d) => d.deploymentName));\n const createProjects = await promptYesNo(ctx, {\n message,\n default: true,\n });\n if (!createProjects) {\n logMessage(\n \"Not linking your existing deployments. If you want to link them later, run `npx convex login --link-deployments`.\",\n );\n logMessage(\n `Visit ${DASHBOARD_HOST} or run \\`npx convex dev\\` to get started with your new account.`,\n );\n return;\n }\n\n const {\n team: { slug: teamSlug },\n } = await validateOrSelectTeam(\n ctx,\n undefined,\n \"Choose a team for your deployments:\",\n );\n let dashboardUrl = teamDashboardUrl(teamSlug);\n for (const deployment of legacyDeployments) {\n const result = await linkSingleDeployment(\n ctx,\n deployment.deploymentName,\n configuredDeployment,\n { teamSlug, projectSlug: null },\n );\n if (deployment.deploymentName === configuredDeployment) {\n dashboardUrl = result.dashboardUrl;\n }\n }\n logFinishedStep(\n `Successfully linked your deployments! Visit ${dashboardUrl} to get started.`,\n );\n return;\n }\n\n // Interactive mode: let user choose which legacy deployments to link\n while (true) {\n const currentLegacyDeployments = listLegacyAnonymousDeployments(ctx);\n if (currentLegacyDeployments.length === 0) {\n logMessage(\"All deployments have been linked.\");\n break;\n }\n logMessage(\n getDeploymentListMessage(\n currentLegacyDeployments.map((d) => d.deploymentName),\n ),\n );\n const deploymentToLink = await promptSearch(ctx, {\n message: \"Which deployment would you like to link to your account?\",\n choices: currentLegacyDeployments.map((d) => ({\n name: d.deploymentName,\n value: d.deploymentName,\n })),\n });\n\n await linkSingleDeployment(ctx, deploymentToLink, configuredDeployment);\n\n const shouldContinue = await promptYesNo(ctx, {\n message: \"Would you like to link another deployment?\",\n default: true,\n });\n if (!shouldContinue) {\n break;\n }\n }\n}\n\n/**\n * Link a single deployment to a project, prompting for team and project selection.\n * Updates env vars if this is the currently configured deployment.\n */\nasync function linkSingleDeployment(\n ctx: Context,\n deploymentName: string,\n configuredDeployment: string | null,\n options?: {\n teamSlug?: string;\n projectSlug?: string | null;\n },\n): Promise<{ dashboardUrl: string }> {\n const { team } = await validateOrSelectTeam(\n ctx,\n options?.teamSlug,\n \"Choose a team for your deployment:\",\n );\n\n const projectSlug =\n options?.projectSlug ??\n (\n await selectProject(ctx, \"ask\", {\n team: team.slug,\n devDeployment: \"local\",\n defaultProjectName: removeAnonymousPrefix(deploymentName),\n })\n ).projectSlug;\n\n const linkedDeployment = await handleLinkToProject(ctx, {\n deploymentName,\n teamSlug: team.slug,\n teamId: team.id,\n projectSlug,\n });\n\n if (deploymentName === configuredDeployment) {\n await updateEnvAndConfigForDeploymentSelection(\n ctx,\n {\n url: linkedDeployment.deploymentUrl,\n deploymentName: linkedDeployment.deploymentName,\n teamSlug: team.slug,\n projectSlug: linkedDeployment.projectSlug,\n deploymentType: \"local\",\n },\n configuredDeployment,\n );\n }\n\n return {\n dashboardUrl: deploymentDashboardUrlPage(\n linkedDeployment.deploymentName,\n \"\",\n ),\n };\n}\n\nfunction getDeploymentListMessage(anonymousDeploymentNames: string[]) {\n let message = `You have ${anonymousDeploymentNames.length} existing deployments.`;\n message += `\\n\\nDeployments:`;\n for (const deploymentName of anonymousDeploymentNames) {\n message += `\\n- ${deploymentName}`;\n }\n return message;\n}\n\nfunction getMessage(anonymousDeploymentNames: string[]) {\n if (anonymousDeploymentNames.length === 1) {\n return `Would you like to link your existing deployment to your account? (\"${anonymousDeploymentNames[0]}\")`;\n }\n let message = `You have ${anonymousDeploymentNames.length} existing deployments. Would you like to link them to your account?`;\n message += `\\n\\nDeployments:`;\n for (const deploymentName of anonymousDeploymentNames) {\n message += `\\n- ${deploymentName}`;\n }\n message += `\\n\\nYou can alternatively run \\`npx convex login --link-deployments\\` to interactively choose which deployments to add.`;\n return message;\n}\n"],
|
|
5
|
-
"mappings": "
|
|
4
|
+
"sourcesContent": ["import { Command, Option } from \"@commander-js/extra-typings\";\nimport * as dotenv from \"dotenv\";\nimport { BigBrainAuth, Context, oneoffContext } from \"../bundler/context.js\";\nimport { logFinishedStep, logMessage, logWarning } from \"../bundler/log.js\";\nimport {\n checkAuthorization,\n isAuthorizedHeader,\n performLogin,\n} from \"./lib/login.js\";\nimport {\n loadProjectLocalConfig,\n loadUuidForAnonymousUser,\n} from \"./lib/localDeployment/filePaths.js\";\nimport {\n handleLinkToProject,\n listLegacyAnonymousDeployments,\n} from \"./lib/localDeployment/anonymous.js\";\nimport {\n DASHBOARD_HOST,\n deploymentDashboardUrlPage,\n teamDashboardUrl,\n} from \"./lib/dashboard.js\";\nimport { promptSearch, promptYesNo } from \"./lib/utils/prompts.js\";\nimport {\n CONVEX_DEPLOY_KEY_ENV_VAR_NAME,\n CONVEX_DEPLOYMENT_TOKEN_ENV_VAR_NAME,\n ENV_VAR_FILE_PATH,\n validateOrSelectTeam,\n} from \"./lib/utils/utils.js\";\nimport {\n selectProject,\n updateEnvAndConfigForDeploymentSelection,\n} from \"./configure.js\";\nimport {\n getDeploymentSelection,\n shouldAllowAnonymousDevelopment,\n} from \"./lib/deploymentSelection.js\";\nimport {\n isAnonymousDeployment,\n removeAnonymousPrefix,\n} from \"./lib/deployment.js\";\nimport {\n readGlobalConfig,\n globalConfigPath,\n} from \"./lib/utils/globalConfig.js\";\nimport { getTeamsForUser } from \"./lib/api.js\";\n\n/**\n * The env file a deploy key came from, or null if it came from the shell.\n * `dotenv` doesn't overwrite variables that are already set, so a value from\n * the shell outranks these files -- match on the value to tell them apart.\n */\nfunction deployKeyEnvFile(\n ctx: Context,\n envVarName: string,\n value: string,\n): string | null {\n for (const file of [ENV_VAR_FILE_PATH, \".env\"]) {\n if (!ctx.fs.exists(file)) {\n continue;\n }\n if (dotenv.parse(ctx.fs.readUtf8File(file))[envVarName] === value) {\n return file;\n }\n }\n return null;\n}\n\n/**\n * A project or deployment key in the environment outranks the account token for\n * commands run from this directory, and an expired one makes the CLI look\n * logged out, so report it separately from the account.\n */\nasync function reportDeployKeyInWorkingDirectory(\n ctx: Context,\n auth: BigBrainAuth | null,\n) {\n // A preview deploy key is only used when there's no account token at all.\n if (\n auth === null ||\n auth.kind === \"accessToken\" ||\n auth.kind === \"previewDeployKey\"\n ) {\n return;\n }\n const key = auth.kind === \"projectKey\" ? auth.projectKey : auth.deploymentKey;\n const envVarName = process.env[CONVEX_DEPLOY_KEY_ENV_VAR_NAME]\n ? CONVEX_DEPLOY_KEY_ENV_VAR_NAME\n : CONVEX_DEPLOYMENT_TOKEN_ENV_VAR_NAME;\n const envFile = deployKeyEnvFile(ctx, envVarName, key);\n const source = envFile ?? \"shell environment\";\n // Big Brain only strips a `project:`/`team:` prefix itself, so a deployment\n // key authorizes only without its `dev:`/`prod:` prefix. Split on the first\n // `|` like the server does, so a secret containing one survives.\n const secret = key.slice(key.indexOf(\"|\") + 1);\n if (await isAuthorizedHeader(ctx, `Bearer ${secret}`)) {\n logMessage(`Working Directory: Valid ${envVarName} in ${source}`);\n return;\n }\n logWarning(`Working Directory: Invalid ${envVarName} in ${source}`);\n}\n\nconst loginStatus = new Command(\"status\")\n .description(\"Check login status and list accessible teams\")\n .allowExcessArguments(false)\n .action(async () => {\n const ctx = await oneoffContext({\n url: undefined,\n adminKey: undefined,\n envFile: undefined,\n });\n\n // `_updateBigBrainAuth` below replaces any deploy key in `ctx` with the\n // account token, so read the deploy key first.\n const auth = ctx.bigBrainAuth();\n\n const globalConfig = readGlobalConfig(ctx);\n if (globalConfig === null) {\n logMessage(`No Convex account token found in: ${globalConfigPath()}`);\n logMessage(\"Status: Not logged in\");\n await reportDeployKeyInWorkingDirectory(ctx, auth);\n return;\n }\n logMessage(`Convex account token found in: ${globalConfigPath()}`);\n\n const accessToken = globalConfig.accessToken;\n if (!(await isAuthorizedHeader(ctx, `Bearer ${accessToken}`))) {\n logMessage(\"Status: Not logged in\");\n await reportDeployKeyInWorkingDirectory(ctx, auth);\n return;\n }\n\n logMessage(\"Status: Logged in\");\n // Describe the account, even if a deploy key outranks it for other commands.\n ctx._updateBigBrainAuth({\n kind: \"accessToken\",\n header: `Bearer ${accessToken}`,\n accessToken,\n });\n const teams = await getTeamsForUser(ctx);\n logMessage(\n `Teams: ${teams.length} team${teams.length === 1 ? \"\" : \"s\"} accessible`,\n );\n for (const team of teams) {\n logMessage(` - ${team.name} (${team.slug})`);\n }\n await reportDeployKeyInWorkingDirectory(ctx, auth);\n });\n\nexport const login = new Command(\"login\")\n .description(\"Login to Convex\")\n .allowExcessArguments(false)\n .option(\n \"--device-name <name>\",\n \"Provide a name for the device being authorized\",\n )\n .option(\n \"-f, --force\",\n \"Proceed with login even if a valid access token already exists for this device\",\n )\n .option(\n \"--no-open\",\n \"Don't automatically open the login link in the default browser\",\n )\n .addOption(\n new Option(\n \"--login-flow <mode>\",\n `How to log in; defaults to guessing based on the environment.`,\n )\n .choices([\"paste\", \"auto\", \"poll\"] as const)\n .default(\"auto\" as const),\n )\n .addOption(new Option(\"--link-deployments\").hideHelp())\n // These options are hidden from the help/usage message, but allow overriding settings for testing.\n // Change the auth credentials with the auth provider\n .addOption(new Option(\"--override-auth-url <url>\").hideHelp())\n .addOption(new Option(\"--override-auth-client <id>\").hideHelp())\n .addOption(new Option(\"--override-auth-username <username>\").hideHelp())\n .addOption(new Option(\"--override-auth-password <password>\").hideHelp())\n // Skip the auth provider login and directly use this access token\n .addOption(new Option(\"--override-access-token <token>\").hideHelp())\n // Automatically accept opt ins without prompting\n .addOption(new Option(\"--accept-opt-ins\").hideHelp())\n // Dump the access token from the auth provider and skip authorization with Convex\n .addOption(new Option(\"--dump-access-token\").hideHelp())\n // Hidden option for tests to check if the user is logged in.\n .addOption(new Option(\"--check-login\").hideHelp())\n // Redirect to Vercel SSO integration URL\n .addOption(\n new Option(\n \"--vercel\",\n \"Redirect to Vercel SSO integration for login\",\n ).hideHelp(),\n )\n // Override the Vercel URL slug (defaults to 'convex')\n .addOption(new Option(\"--vercel-override <slug>\").hideHelp())\n .addCommand(loginStatus)\n .addHelpCommand(false)\n .action(async (options, cmd: Command) => {\n const ctx = await oneoffContext({\n url: undefined,\n adminKey: undefined,\n envFile: undefined,\n });\n if (\n !options.force &&\n (await checkAuthorization(ctx, !!options.acceptOptIns))\n ) {\n logFinishedStep(\n \"This device has previously been authorized and is ready for use with Convex.\",\n );\n await handleLinkingDeployments(ctx, {\n interactive: !!options.linkDeployments,\n });\n return;\n }\n if (!options.force && options.checkLogin) {\n const isLoggedIn = await checkAuthorization(ctx, !!options.acceptOptIns);\n if (!isLoggedIn) {\n return ctx.crash({\n exitCode: 1,\n errorType: \"fatal\",\n errForSentry: \"You are not logged in.\",\n printedMessage: \"You are not logged in.\",\n });\n }\n }\n if (!!options.overrideAuthUsername !== !!options.overrideAuthPassword) {\n cmd.error(\n \"If overriding credentials, both username and password must be provided\",\n );\n }\n\n const uuid = loadUuidForAnonymousUser(ctx);\n await performLogin(ctx, {\n ...options,\n anonymousId: uuid,\n vercel: options.vercel,\n vercelOverride: options.vercelOverride,\n });\n\n await handleLinkingDeployments(ctx, {\n interactive: !!options.linkDeployments,\n });\n });\n\nasync function handleLinkingDeployments(\n ctx: Context,\n args: {\n interactive: boolean;\n },\n) {\n if (!shouldAllowAnonymousDevelopment()) {\n return;\n }\n\n // Check for project-local anonymous deployment first - this takes priority\n const projectLocal = loadProjectLocalConfig(ctx);\n if (\n projectLocal !== null &&\n isAnonymousDeployment(projectLocal.deploymentName)\n ) {\n const shouldLink = await promptYesNo(ctx, {\n message: `Would you like to link your existing deployment to your account? (\"${projectLocal.deploymentName}\")`,\n default: true,\n });\n if (!shouldLink) {\n logMessage(\n \"Not linking your existing deployment. If you want to link it later, run `npx convex login --link-deployments`.\",\n );\n logMessage(\n `Visit ${DASHBOARD_HOST} or run \\`npx convex dev\\` to get started with your new account.`,\n );\n return;\n }\n\n const { dashboardUrl } = await linkSingleDeployment(\n ctx,\n projectLocal.deploymentName,\n projectLocal.deploymentName,\n );\n logFinishedStep(`Visit ${dashboardUrl} to get started.`);\n return;\n }\n\n // No project-local deployment - check for legacy deployments\n const legacyDeployments = listLegacyAnonymousDeployments(ctx);\n if (legacyDeployments.length === 0) {\n if (args.interactive) {\n logMessage(\n \"It doesn't look like you have any deployments to link. You can run `npx convex dev` to set up a new project or select an existing one.\",\n );\n }\n return;\n }\n\n // Get the currently configured deployment (if any) for env var updates\n const deploymentSelection = await getDeploymentSelection(ctx, {\n url: undefined,\n adminKey: undefined,\n envFile: undefined,\n });\n const configuredDeployment =\n deploymentSelection.kind === \"anonymous\"\n ? deploymentSelection.deploymentName\n : null;\n\n if (!args.interactive) {\n // Non-interactive: link all legacy deployments automatically\n const message = getMessage(legacyDeployments.map((d) => d.deploymentName));\n const createProjects = await promptYesNo(ctx, {\n message,\n default: true,\n });\n if (!createProjects) {\n logMessage(\n \"Not linking your existing deployments. If you want to link them later, run `npx convex login --link-deployments`.\",\n );\n logMessage(\n `Visit ${DASHBOARD_HOST} or run \\`npx convex dev\\` to get started with your new account.`,\n );\n return;\n }\n\n const {\n team: { slug: teamSlug },\n } = await validateOrSelectTeam(\n ctx,\n undefined,\n \"Choose a team for your deployments:\",\n );\n let dashboardUrl = teamDashboardUrl(teamSlug);\n for (const deployment of legacyDeployments) {\n const result = await linkSingleDeployment(\n ctx,\n deployment.deploymentName,\n configuredDeployment,\n { teamSlug, projectSlug: null },\n );\n if (deployment.deploymentName === configuredDeployment) {\n dashboardUrl = result.dashboardUrl;\n }\n }\n logFinishedStep(\n `Successfully linked your deployments! Visit ${dashboardUrl} to get started.`,\n );\n return;\n }\n\n // Interactive mode: let user choose which legacy deployments to link\n while (true) {\n const currentLegacyDeployments = listLegacyAnonymousDeployments(ctx);\n if (currentLegacyDeployments.length === 0) {\n logMessage(\"All deployments have been linked.\");\n break;\n }\n logMessage(\n getDeploymentListMessage(\n currentLegacyDeployments.map((d) => d.deploymentName),\n ),\n );\n const deploymentToLink = await promptSearch(ctx, {\n message: \"Which deployment would you like to link to your account?\",\n choices: currentLegacyDeployments.map((d) => ({\n name: d.deploymentName,\n value: d.deploymentName,\n })),\n });\n\n await linkSingleDeployment(ctx, deploymentToLink, configuredDeployment);\n\n const shouldContinue = await promptYesNo(ctx, {\n message: \"Would you like to link another deployment?\",\n default: true,\n });\n if (!shouldContinue) {\n break;\n }\n }\n}\n\n/**\n * Link a single deployment to a project, prompting for team and project selection.\n * Updates env vars if this is the currently configured deployment.\n */\nasync function linkSingleDeployment(\n ctx: Context,\n deploymentName: string,\n configuredDeployment: string | null,\n options?: {\n teamSlug?: string;\n projectSlug?: string | null;\n },\n): Promise<{ dashboardUrl: string }> {\n const { team } = await validateOrSelectTeam(\n ctx,\n options?.teamSlug,\n \"Choose a team for your deployment:\",\n );\n\n const projectSlug =\n options?.projectSlug ??\n (\n await selectProject(ctx, \"ask\", {\n team: team.slug,\n devDeployment: \"local\",\n defaultProjectName: removeAnonymousPrefix(deploymentName),\n })\n ).projectSlug;\n\n const linkedDeployment = await handleLinkToProject(ctx, {\n deploymentName,\n teamSlug: team.slug,\n teamId: team.id,\n projectSlug,\n });\n\n if (deploymentName === configuredDeployment) {\n await updateEnvAndConfigForDeploymentSelection(\n ctx,\n {\n url: linkedDeployment.deploymentUrl,\n deploymentName: linkedDeployment.deploymentName,\n teamSlug: team.slug,\n projectSlug: linkedDeployment.projectSlug,\n deploymentType: \"local\",\n },\n configuredDeployment,\n );\n }\n\n return {\n dashboardUrl: deploymentDashboardUrlPage(\n linkedDeployment.deploymentName,\n \"\",\n ),\n };\n}\n\nfunction getDeploymentListMessage(anonymousDeploymentNames: string[]) {\n let message = `You have ${anonymousDeploymentNames.length} existing deployments.`;\n message += `\\n\\nDeployments:`;\n for (const deploymentName of anonymousDeploymentNames) {\n message += `\\n- ${deploymentName}`;\n }\n return message;\n}\n\nfunction getMessage(anonymousDeploymentNames: string[]) {\n if (anonymousDeploymentNames.length === 1) {\n return `Would you like to link your existing deployment to your account? (\"${anonymousDeploymentNames[0]}\")`;\n }\n let message = `You have ${anonymousDeploymentNames.length} existing deployments. Would you like to link them to your account?`;\n message += `\\n\\nDeployments:`;\n for (const deploymentName of anonymousDeploymentNames) {\n message += `\\n- ${deploymentName}`;\n }\n message += `\\n\\nYou can alternatively run \\`npx convex login --link-deployments\\` to interactively choose which deployments to add.`;\n return message;\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,2BAAgC;AAChC,aAAwB;AACxB,qBAAqD;AACrD,iBAAwD;AACxD,mBAIO;AACP,uBAGO;AACP,uBAGO;AACP,uBAIO;AACP,qBAA0C;AAC1C,mBAKO;AACP,uBAGO;AACP,iCAGO;AACP,wBAGO;AACP,0BAGO;AACP,iBAAgC;AAOhC,SAAS,iBACP,KACA,YACA,OACe;AACf,aAAW,QAAQ,CAAC,gCAAmB,MAAM,GAAG;AAC9C,QAAI,CAAC,IAAI,GAAG,OAAO,IAAI,GAAG;AACxB;AAAA,IACF;AACA,QAAI,OAAO,MAAM,IAAI,GAAG,aAAa,IAAI,CAAC,EAAE,UAAU,MAAM,OAAO;AACjE,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;AAOA,eAAe,kCACb,KACA,MACA;AAEA,MACE,SAAS,QACT,KAAK,SAAS,iBACd,KAAK,SAAS,oBACd;AACA;AAAA,EACF;AACA,QAAM,MAAM,KAAK,SAAS,eAAe,KAAK,aAAa,KAAK;AAChE,QAAM,aAAa,QAAQ,IAAI,2CAA8B,IACzD,8CACA;AACJ,QAAM,UAAU,iBAAiB,KAAK,YAAY,GAAG;AACrD,QAAM,SAAS,WAAW;AAI1B,QAAM,SAAS,IAAI,MAAM,IAAI,QAAQ,GAAG,IAAI,CAAC;AAC7C,MAAI,UAAM,iCAAmB,KAAK,UAAU,MAAM,EAAE,GAAG;AACrD,+BAAW,4BAA4B,UAAU,OAAO,MAAM,EAAE;AAChE;AAAA,EACF;AACA,6BAAW,8BAA8B,UAAU,OAAO,MAAM,EAAE;AACpE;AAEA,MAAM,cAAc,IAAI,6BAAQ,QAAQ,EACrC,YAAY,8CAA8C,EAC1D,qBAAqB,KAAK,EAC1B,OAAO,YAAY;AAClB,QAAM,MAAM,UAAM,8BAAc;AAAA,IAC9B,KAAK;AAAA,IACL,UAAU;AAAA,IACV,SAAS;AAAA,EACX,CAAC;AAID,QAAM,OAAO,IAAI,aAAa;AAE9B,QAAM,mBAAe,sCAAiB,GAAG;AACzC,MAAI,iBAAiB,MAAM;AACzB,+BAAW,yCAAqC,sCAAiB,CAAC,EAAE;AACpE,+BAAW,uBAAuB;AAClC,UAAM,kCAAkC,KAAK,IAAI;AACjD;AAAA,EACF;AACA,6BAAW,sCAAkC,sCAAiB,CAAC,EAAE;AAEjE,QAAM,cAAc,aAAa;AACjC,MAAI,CAAE,UAAM,iCAAmB,KAAK,UAAU,WAAW,EAAE,GAAI;AAC7D,+BAAW,uBAAuB;AAClC,UAAM,kCAAkC,KAAK,IAAI;AACjD;AAAA,EACF;AAEA,6BAAW,mBAAmB;AAE9B,MAAI,oBAAoB;AAAA,IACtB,MAAM;AAAA,IACN,QAAQ,UAAU,WAAW;AAAA,IAC7B;AAAA,EACF,CAAC;AACD,QAAM,QAAQ,UAAM,4BAAgB,GAAG;AACvC;AAAA,IACE,UAAU,MAAM,MAAM,QAAQ,MAAM,WAAW,IAAI,KAAK,GAAG;AAAA,EAC7D;AACA,aAAW,QAAQ,OAAO;AACxB,+BAAW,OAAO,KAAK,IAAI,KAAK,KAAK,IAAI,GAAG;AAAA,EAC9C;AACA,QAAM,kCAAkC,KAAK,IAAI;AACnD,CAAC;AAEI,MAAM,QAAQ,IAAI,6BAAQ,OAAO,EACrC,YAAY,iBAAiB,EAC7B,qBAAqB,KAAK,EAC1B;AAAA,EACC;AAAA,EACA;AACF,EACC;AAAA,EACC;AAAA,EACA;AACF,EACC;AAAA,EACC;AAAA,EACA;AACF,EACC;AAAA,EACC,IAAI;AAAA,IACF;AAAA,IACA;AAAA,EACF,EACG,QAAQ,CAAC,SAAS,QAAQ,MAAM,CAAU,EAC1C,QAAQ,MAAe;AAC5B,EACC,UAAU,IAAI,4BAAO,oBAAoB,EAAE,SAAS,CAAC,EAGrD,UAAU,IAAI,4BAAO,2BAA2B,EAAE,SAAS,CAAC,EAC5D,UAAU,IAAI,4BAAO,6BAA6B,EAAE,SAAS,CAAC,EAC9D,UAAU,IAAI,4BAAO,qCAAqC,EAAE,SAAS,CAAC,EACtE,UAAU,IAAI,4BAAO,qCAAqC,EAAE,SAAS,CAAC,EAEtE,UAAU,IAAI,4BAAO,iCAAiC,EAAE,SAAS,CAAC,EAElE,UAAU,IAAI,4BAAO,kBAAkB,EAAE,SAAS,CAAC,EAEnD,UAAU,IAAI,4BAAO,qBAAqB,EAAE,SAAS,CAAC,EAEtD,UAAU,IAAI,4BAAO,eAAe,EAAE,SAAS,CAAC,EAEhD;AAAA,EACC,IAAI;AAAA,IACF;AAAA,IACA;AAAA,EACF,EAAE,SAAS;AACb,EAEC,UAAU,IAAI,4BAAO,0BAA0B,EAAE,SAAS,CAAC,EAC3D,WAAW,WAAW,EACtB,eAAe,KAAK,EACpB,OAAO,OAAO,SAAS,QAAiB;AACvC,QAAM,MAAM,UAAM,8BAAc;AAAA,IAC9B,KAAK;AAAA,IACL,UAAU;AAAA,IACV,SAAS;AAAA,EACX,CAAC;AACD,MACE,CAAC,QAAQ,SACR,UAAM,iCAAmB,KAAK,CAAC,CAAC,QAAQ,YAAY,GACrD;AACA;AAAA,MACE;AAAA,IACF;AACA,UAAM,yBAAyB,KAAK;AAAA,MAClC,aAAa,CAAC,CAAC,QAAQ;AAAA,IACzB,CAAC;AACD;AAAA,EACF;AACA,MAAI,CAAC,QAAQ,SAAS,QAAQ,YAAY;AACxC,UAAM,aAAa,UAAM,iCAAmB,KAAK,CAAC,CAAC,QAAQ,YAAY;AACvE,QAAI,CAAC,YAAY;AACf,aAAO,IAAI,MAAM;AAAA,QACf,UAAU;AAAA,QACV,WAAW;AAAA,QACX,cAAc;AAAA,QACd,gBAAgB;AAAA,MAClB,CAAC;AAAA,IACH;AAAA,EACF;AACA,MAAI,CAAC,CAAC,QAAQ,yBAAyB,CAAC,CAAC,QAAQ,sBAAsB;AACrE,QAAI;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,QAAM,WAAO,2CAAyB,GAAG;AACzC,YAAM,2BAAa,KAAK;AAAA,IACtB,GAAG;AAAA,IACH,aAAa;AAAA,IACb,QAAQ,QAAQ;AAAA,IAChB,gBAAgB,QAAQ;AAAA,EAC1B,CAAC;AAED,QAAM,yBAAyB,KAAK;AAAA,IAClC,aAAa,CAAC,CAAC,QAAQ;AAAA,EACzB,CAAC;AACH,CAAC;AAEH,eAAe,yBACb,KACA,MAGA;AACA,MAAI,KAAC,4DAAgC,GAAG;AACtC;AAAA,EACF;AAGA,QAAM,mBAAe,yCAAuB,GAAG;AAC/C,MACE,iBAAiB,YACjB,yCAAsB,aAAa,cAAc,GACjD;AACA,UAAM,aAAa,UAAM,4BAAY,KAAK;AAAA,MACxC,SAAS,sEAAsE,aAAa,cAAc;AAAA,MAC1G,SAAS;AAAA,IACX,CAAC;AACD,QAAI,CAAC,YAAY;AACf;AAAA,QACE;AAAA,MACF;AACA;AAAA,QACE,SAAS,+BAAc;AAAA,MACzB;AACA;AAAA,IACF;AAEA,UAAM,EAAE,aAAa,IAAI,MAAM;AAAA,MAC7B;AAAA,MACA,aAAa;AAAA,MACb,aAAa;AAAA,IACf;AACA,oCAAgB,SAAS,YAAY,kBAAkB;AACvD;AAAA,EACF;AAGA,QAAM,wBAAoB,iDAA+B,GAAG;AAC5D,MAAI,kBAAkB,WAAW,GAAG;AAClC,QAAI,KAAK,aAAa;AACpB;AAAA,QACE;AAAA,MACF;AAAA,IACF;AACA;AAAA,EACF;AAGA,QAAM,sBAAsB,UAAM,mDAAuB,KAAK;AAAA,IAC5D,KAAK;AAAA,IACL,UAAU;AAAA,IACV,SAAS;AAAA,EACX,CAAC;AACD,QAAM,uBACJ,oBAAoB,SAAS,cACzB,oBAAoB,iBACpB;AAEN,MAAI,CAAC,KAAK,aAAa;AAErB,UAAM,UAAU,WAAW,kBAAkB,IAAI,CAAC,MAAM,EAAE,cAAc,CAAC;AACzE,UAAM,iBAAiB,UAAM,4BAAY,KAAK;AAAA,MAC5C;AAAA,MACA,SAAS;AAAA,IACX,CAAC;AACD,QAAI,CAAC,gBAAgB;AACnB;AAAA,QACE;AAAA,MACF;AACA;AAAA,QACE,SAAS,+BAAc;AAAA,MACzB;AACA;AAAA,IACF;AAEA,UAAM;AAAA,MACJ,MAAM,EAAE,MAAM,SAAS;AAAA,IACzB,IAAI,UAAM;AAAA,MACR;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,QAAI,mBAAe,mCAAiB,QAAQ;AAC5C,eAAW,cAAc,mBAAmB;AAC1C,YAAM,SAAS,MAAM;AAAA,QACnB;AAAA,QACA,WAAW;AAAA,QACX;AAAA,QACA,EAAE,UAAU,aAAa,KAAK;AAAA,MAChC;AACA,UAAI,WAAW,mBAAmB,sBAAsB;AACtD,uBAAe,OAAO;AAAA,MACxB;AAAA,IACF;AACA;AAAA,MACE,+CAA+C,YAAY;AAAA,IAC7D;AACA;AAAA,EACF;AAGA,SAAO,MAAM;AACX,UAAM,+BAA2B,iDAA+B,GAAG;AACnE,QAAI,yBAAyB,WAAW,GAAG;AACzC,iCAAW,mCAAmC;AAC9C;AAAA,IACF;AACA;AAAA,MACE;AAAA,QACE,yBAAyB,IAAI,CAAC,MAAM,EAAE,cAAc;AAAA,MACtD;AAAA,IACF;AACA,UAAM,mBAAmB,UAAM,6BAAa,KAAK;AAAA,MAC/C,SAAS;AAAA,MACT,SAAS,yBAAyB,IAAI,CAAC,OAAO;AAAA,QAC5C,MAAM,EAAE;AAAA,QACR,OAAO,EAAE;AAAA,MACX,EAAE;AAAA,IACJ,CAAC;AAED,UAAM,qBAAqB,KAAK,kBAAkB,oBAAoB;AAEtE,UAAM,iBAAiB,UAAM,4BAAY,KAAK;AAAA,MAC5C,SAAS;AAAA,MACT,SAAS;AAAA,IACX,CAAC;AACD,QAAI,CAAC,gBAAgB;AACnB;AAAA,IACF;AAAA,EACF;AACF;AAMA,eAAe,qBACb,KACA,gBACA,sBACA,SAImC;AACnC,QAAM,EAAE,KAAK,IAAI,UAAM;AAAA,IACrB;AAAA,IACA,SAAS;AAAA,IACT;AAAA,EACF;AAEA,QAAM,cACJ,SAAS,gBAEP,UAAM,gCAAc,KAAK,OAAO;AAAA,IAC9B,MAAM,KAAK;AAAA,IACX,eAAe;AAAA,IACf,wBAAoB,yCAAsB,cAAc;AAAA,EAC1D,CAAC,GACD;AAEJ,QAAM,mBAAmB,UAAM,sCAAoB,KAAK;AAAA,IACtD;AAAA,IACA,UAAU,KAAK;AAAA,IACf,QAAQ,KAAK;AAAA,IACb;AAAA,EACF,CAAC;AAED,MAAI,mBAAmB,sBAAsB;AAC3C,cAAM;AAAA,MACJ;AAAA,MACA;AAAA,QACE,KAAK,iBAAiB;AAAA,QACtB,gBAAgB,iBAAiB;AAAA,QACjC,UAAU,KAAK;AAAA,QACf,aAAa,iBAAiB;AAAA,QAC9B,gBAAgB;AAAA,MAClB;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL,kBAAc;AAAA,MACZ,iBAAiB;AAAA,MACjB;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,yBAAyB,0BAAoC;AACpE,MAAI,UAAU,YAAY,yBAAyB,MAAM;AACzD,aAAW;AAAA;AAAA;AACX,aAAW,kBAAkB,0BAA0B;AACrD,eAAW;AAAA,IAAO,cAAc;AAAA,EAClC;AACA,SAAO;AACT;AAEA,SAAS,WAAW,0BAAoC;AACtD,MAAI,yBAAyB,WAAW,GAAG;AACzC,WAAO,sEAAsE,yBAAyB,CAAC,CAAC;AAAA,EAC1G;AACA,MAAI,UAAU,YAAY,yBAAyB,MAAM;AACzD,aAAW;AAAA;AAAA;AACX,aAAW,kBAAkB,0BAA0B;AACrD,eAAW;AAAA,IAAO,cAAc;AAAA,EAClC;AACA,aAAW;AAAA;AAAA;AACX,SAAO;AACT;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/cjs/index.js
CHANGED
package/dist/cjs/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/index.ts"],
|
|
4
|
-
"sourcesContent": ["export const version = \"1.
|
|
4
|
+
"sourcesContent": ["export const version = \"1.44.0\";\n"],
|
|
5
5
|
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAO,MAAM,UAAU;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -65,39 +65,37 @@ function ConvexProviderWithAuth({
|
|
|
65
65
|
setIsRefreshing(false);
|
|
66
66
|
}
|
|
67
67
|
const isAuthenticated = authProviderAuthenticated && (isConvexAuthenticated ?? false);
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
/* @__PURE__ */ import_react.default.createElement(
|
|
78
|
-
ConvexAuthStateFirstEffect,
|
|
79
|
-
{
|
|
80
|
-
authProviderAuthenticated,
|
|
81
|
-
fetchAccessToken,
|
|
82
|
-
authProviderLoading,
|
|
83
|
-
client,
|
|
84
|
-
setIsConvexAuthenticated,
|
|
85
|
-
setIsRefreshing
|
|
86
|
-
}
|
|
87
|
-
),
|
|
88
|
-
/* @__PURE__ */ import_react.default.createElement(import_client2.ConvexProvider, { client }, children),
|
|
89
|
-
/* @__PURE__ */ import_react.default.createElement(
|
|
90
|
-
ConvexAuthStateLastEffect,
|
|
91
|
-
{
|
|
92
|
-
authProviderAuthenticated,
|
|
93
|
-
fetchAccessToken,
|
|
94
|
-
authProviderLoading,
|
|
95
|
-
client,
|
|
96
|
-
setIsConvexAuthenticated,
|
|
97
|
-
setIsRefreshing
|
|
98
|
-
}
|
|
99
|
-
)
|
|
68
|
+
const isLoading = isConvexAuthenticated === null;
|
|
69
|
+
const isRefreshingWhileAuthenticated = isRefreshing && isAuthenticated;
|
|
70
|
+
const authState = (0, import_react.useMemo)(
|
|
71
|
+
() => ({
|
|
72
|
+
isLoading,
|
|
73
|
+
isAuthenticated,
|
|
74
|
+
isRefreshing: isRefreshingWhileAuthenticated
|
|
75
|
+
}),
|
|
76
|
+
[isLoading, isAuthenticated, isRefreshingWhileAuthenticated]
|
|
100
77
|
);
|
|
78
|
+
return /* @__PURE__ */ import_react.default.createElement(ConvexAuthContext.Provider, { value: authState }, /* @__PURE__ */ import_react.default.createElement(
|
|
79
|
+
ConvexAuthStateFirstEffect,
|
|
80
|
+
{
|
|
81
|
+
authProviderAuthenticated,
|
|
82
|
+
fetchAccessToken,
|
|
83
|
+
authProviderLoading,
|
|
84
|
+
client,
|
|
85
|
+
setIsConvexAuthenticated,
|
|
86
|
+
setIsRefreshing
|
|
87
|
+
}
|
|
88
|
+
), /* @__PURE__ */ import_react.default.createElement(import_client2.ConvexProvider, { client }, children), /* @__PURE__ */ import_react.default.createElement(
|
|
89
|
+
ConvexAuthStateLastEffect,
|
|
90
|
+
{
|
|
91
|
+
authProviderAuthenticated,
|
|
92
|
+
fetchAccessToken,
|
|
93
|
+
authProviderLoading,
|
|
94
|
+
client,
|
|
95
|
+
setIsConvexAuthenticated,
|
|
96
|
+
setIsRefreshing
|
|
97
|
+
}
|
|
98
|
+
));
|
|
101
99
|
}
|
|
102
100
|
function ConvexAuthStateFirstEffect({
|
|
103
101
|
authProviderAuthenticated,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/react/ConvexAuthState.tsx"],
|
|
4
|
-
"sourcesContent": ["import React, {\n createContext,\n ReactNode,\n useContext,\n useEffect,\n useState,\n} from \"react\";\nimport { AuthTokenFetcher } from \"../browser/sync/client.js\";\nimport { ConvexProvider } from \"./client.js\";\n\n// Until we can import from our own entry points (requires TypeScript 4.7),\n// just describe the interface enough to help users pass the right type.\ntype IConvexReactClient = {\n setAuth(\n fetchToken: AuthTokenFetcher,\n onChange: (isAuthenticated: boolean) => void,\n onRefreshChange?: (isRefreshing: boolean) => void,\n ): void;\n clearAuth(): void;\n};\n\n/**\n * Type representing the state of an auth integration with Convex.\n *\n * - `isLoading`: the client is still resolving the initial auth state and\n * waiting for the server to confirm the current token.\n * - `isAuthenticated`: the server has confirmed the current token.\n * - `isRefreshing`: the server rejected a previously-confirmed token and the\n * socket is paused while a replacement is fetched. Only ever `true` when\n * `isAuthenticated` is also `true`. Routine background token rotation does\n * not trigger this state.\n *\n * @public\n */\nexport type ConvexAuthState = {\n isLoading: boolean;\n isAuthenticated: boolean;\n isRefreshing: boolean;\n};\n\nconst ConvexAuthContext = createContext<ConvexAuthState>(undefined as any);\n\n/**\n * Get the {@link ConvexAuthState} within a React component.\n *\n * This relies on a Convex auth integration provider being above in the React\n * component tree. See {@link ConvexAuthState} for the meaning of each field.\n *\n * @returns The current {@link ConvexAuthState}.\n *\n * @public\n */\nexport function useConvexAuth(): {\n isLoading: boolean;\n isAuthenticated: boolean;\n isRefreshing: boolean;\n} {\n const authContext = useContext(ConvexAuthContext);\n if (authContext === undefined) {\n throw new Error(\n \"Could not find `ConvexProviderWithAuth` (or `ConvexProviderWithClerk` \" +\n \"or `ConvexProviderWithAuth0`) \" +\n \"as an ancestor component. This component may be missing, or you \" +\n \"might have two instances of the `convex/react` module loaded in your \" +\n \"project.\",\n );\n }\n return authContext;\n}\n\n/**\n * A replacement for {@link ConvexProvider} which additionally provides\n * {@link ConvexAuthState} to descendants of this component.\n *\n * Use this to integrate any auth provider with Convex. The `useAuth` prop\n * should be a React hook that returns the provider's authentication state\n * and a function to fetch a JWT access token.\n *\n * If the `useAuth` prop function updates causing a rerender then auth state\n * will transition to loading and the `fetchAccessToken()` function called again.\n *\n * See [Custom Auth Integration](https://docs.convex.dev/auth/advanced/custom-auth) for more information.\n *\n * @public\n */\nexport function ConvexProviderWithAuth({\n children,\n client,\n useAuth,\n}: {\n children?: ReactNode;\n client: IConvexReactClient;\n useAuth: () => {\n isLoading: boolean;\n isAuthenticated: boolean;\n fetchAccessToken: (args: {\n forceRefreshToken: boolean;\n }) => Promise<string | null>;\n };\n}) {\n const {\n isLoading: authProviderLoading,\n isAuthenticated: authProviderAuthenticated,\n fetchAccessToken,\n } = useAuth();\n const [isConvexAuthenticated, setIsConvexAuthenticated] = useState<\n boolean | null\n >(null);\n const [isRefreshing, setIsRefreshing] = useState<boolean>(false);\n\n // If the useAuth went back to the authProviderLoading state (which is unusual but possible)\n // reset the Convex auth state to null so that we can correctly\n // transition the state from \"loading\" to \"authenticated\"\n // without going through \"unauthenticated\".\n if (authProviderLoading && isConvexAuthenticated !== null) {\n setIsConvexAuthenticated(null);\n setIsRefreshing(false);\n }\n\n // If the useAuth goes to not authenticated then isConvexAuthenticated should reflect that.\n if (\n !authProviderLoading &&\n !authProviderAuthenticated &&\n isConvexAuthenticated !== false\n ) {\n setIsConvexAuthenticated(false);\n setIsRefreshing(false);\n }\n\n const isAuthenticated =\n authProviderAuthenticated && (isConvexAuthenticated ?? false);\n\n
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,
|
|
4
|
+
"sourcesContent": ["import React, {\n createContext,\n ReactNode,\n useContext,\n useEffect,\n useMemo,\n useState,\n} from \"react\";\nimport { AuthTokenFetcher } from \"../browser/sync/client.js\";\nimport { ConvexProvider } from \"./client.js\";\n\n// Until we can import from our own entry points (requires TypeScript 4.7),\n// just describe the interface enough to help users pass the right type.\ntype IConvexReactClient = {\n setAuth(\n fetchToken: AuthTokenFetcher,\n onChange: (isAuthenticated: boolean) => void,\n onRefreshChange?: (isRefreshing: boolean) => void,\n ): void;\n clearAuth(): void;\n};\n\n/**\n * Type representing the state of an auth integration with Convex.\n *\n * - `isLoading`: the client is still resolving the initial auth state and\n * waiting for the server to confirm the current token.\n * - `isAuthenticated`: the server has confirmed the current token.\n * - `isRefreshing`: the server rejected a previously-confirmed token and the\n * socket is paused while a replacement is fetched. Only ever `true` when\n * `isAuthenticated` is also `true`. Routine background token rotation does\n * not trigger this state.\n *\n * @public\n */\nexport type ConvexAuthState = {\n isLoading: boolean;\n isAuthenticated: boolean;\n isRefreshing: boolean;\n};\n\nconst ConvexAuthContext = createContext<ConvexAuthState>(undefined as any);\n\n/**\n * Get the {@link ConvexAuthState} within a React component.\n *\n * This relies on a Convex auth integration provider being above in the React\n * component tree. See {@link ConvexAuthState} for the meaning of each field.\n *\n * @returns The current {@link ConvexAuthState}.\n *\n * @public\n */\nexport function useConvexAuth(): {\n isLoading: boolean;\n isAuthenticated: boolean;\n isRefreshing: boolean;\n} {\n const authContext = useContext(ConvexAuthContext);\n if (authContext === undefined) {\n throw new Error(\n \"Could not find `ConvexProviderWithAuth` (or `ConvexProviderWithClerk` \" +\n \"or `ConvexProviderWithAuth0`) \" +\n \"as an ancestor component. This component may be missing, or you \" +\n \"might have two instances of the `convex/react` module loaded in your \" +\n \"project.\",\n );\n }\n return authContext;\n}\n\n/**\n * A replacement for {@link ConvexProvider} which additionally provides\n * {@link ConvexAuthState} to descendants of this component.\n *\n * Use this to integrate any auth provider with Convex. The `useAuth` prop\n * should be a React hook that returns the provider's authentication state\n * and a function to fetch a JWT access token.\n *\n * If the `useAuth` prop function updates causing a rerender then auth state\n * will transition to loading and the `fetchAccessToken()` function called again.\n *\n * See [Custom Auth Integration](https://docs.convex.dev/auth/advanced/custom-auth) for more information.\n *\n * @public\n */\nexport function ConvexProviderWithAuth({\n children,\n client,\n useAuth,\n}: {\n children?: ReactNode;\n client: IConvexReactClient;\n useAuth: () => {\n isLoading: boolean;\n isAuthenticated: boolean;\n fetchAccessToken: (args: {\n forceRefreshToken: boolean;\n }) => Promise<string | null>;\n };\n}) {\n const {\n isLoading: authProviderLoading,\n isAuthenticated: authProviderAuthenticated,\n fetchAccessToken,\n } = useAuth();\n const [isConvexAuthenticated, setIsConvexAuthenticated] = useState<\n boolean | null\n >(null);\n const [isRefreshing, setIsRefreshing] = useState<boolean>(false);\n\n // If the useAuth went back to the authProviderLoading state (which is unusual but possible)\n // reset the Convex auth state to null so that we can correctly\n // transition the state from \"loading\" to \"authenticated\"\n // without going through \"unauthenticated\".\n if (authProviderLoading && isConvexAuthenticated !== null) {\n setIsConvexAuthenticated(null);\n setIsRefreshing(false);\n }\n\n // If the useAuth goes to not authenticated then isConvexAuthenticated should reflect that.\n if (\n !authProviderLoading &&\n !authProviderAuthenticated &&\n isConvexAuthenticated !== false\n ) {\n setIsConvexAuthenticated(false);\n setIsRefreshing(false);\n }\n\n const isAuthenticated =\n authProviderAuthenticated && (isConvexAuthenticated ?? false);\n const isLoading = isConvexAuthenticated === null;\n const isRefreshingWhileAuthenticated = isRefreshing && isAuthenticated;\n\n // Stabilize the context value's identity so `useConvexAuth()` consumers\n // only re-render when the derived auth state actually changes.\n const authState = useMemo<ConvexAuthState>(\n () => ({\n isLoading,\n isAuthenticated,\n isRefreshing: isRefreshingWhileAuthenticated,\n }),\n [isLoading, isAuthenticated, isRefreshingWhileAuthenticated],\n );\n\n return (\n <ConvexAuthContext.Provider value={authState}>\n <ConvexAuthStateFirstEffect\n authProviderAuthenticated={authProviderAuthenticated}\n fetchAccessToken={fetchAccessToken}\n authProviderLoading={authProviderLoading}\n client={client}\n setIsConvexAuthenticated={setIsConvexAuthenticated}\n setIsRefreshing={setIsRefreshing}\n />\n <ConvexProvider client={client as any}>{children}</ConvexProvider>\n <ConvexAuthStateLastEffect\n authProviderAuthenticated={authProviderAuthenticated}\n fetchAccessToken={fetchAccessToken}\n authProviderLoading={authProviderLoading}\n client={client}\n setIsConvexAuthenticated={setIsConvexAuthenticated}\n setIsRefreshing={setIsRefreshing}\n />\n </ConvexAuthContext.Provider>\n );\n}\n\n// First child ensures we `setAuth` before\n// other child components subscribe to queries via `useEffect`.\nfunction ConvexAuthStateFirstEffect({\n authProviderAuthenticated,\n fetchAccessToken,\n authProviderLoading,\n client,\n setIsConvexAuthenticated,\n setIsRefreshing,\n}: {\n authProviderAuthenticated: boolean;\n fetchAccessToken: (args: {\n forceRefreshToken: boolean;\n }) => Promise<string | null>;\n authProviderLoading: boolean;\n client: IConvexReactClient;\n setIsConvexAuthenticated: React.Dispatch<\n React.SetStateAction<boolean | null>\n >;\n setIsRefreshing: React.Dispatch<React.SetStateAction<boolean>>;\n}) {\n useEffect(() => {\n let isThisEffectRelevant = true;\n if (authProviderAuthenticated) {\n client.setAuth(\n fetchAccessToken,\n (backendReportsIsAuthenticated) => {\n if (isThisEffectRelevant) {\n setIsConvexAuthenticated(() => backendReportsIsAuthenticated);\n }\n },\n (isRefreshing) => {\n if (isThisEffectRelevant) {\n setIsRefreshing(isRefreshing);\n }\n },\n );\n return () => {\n isThisEffectRelevant = false;\n\n // If unmounting or something changed before we finished fetching the token\n // we shouldn't transition to a loaded state.\n setIsConvexAuthenticated((isConvexAuthenticated: boolean | null) =>\n isConvexAuthenticated ? false : null,\n );\n setIsRefreshing(false);\n };\n }\n }, [\n authProviderAuthenticated,\n fetchAccessToken,\n authProviderLoading,\n client,\n setIsConvexAuthenticated,\n setIsRefreshing,\n ]);\n return null;\n}\n\n// Last child ensures we `clearAuth` last,\n// so that queries from unmounted sibling components\n// unsubscribe first and don't rerun without auth on the server\nfunction ConvexAuthStateLastEffect({\n authProviderAuthenticated,\n fetchAccessToken,\n authProviderLoading,\n client,\n setIsConvexAuthenticated,\n setIsRefreshing,\n}: {\n authProviderAuthenticated: boolean;\n fetchAccessToken: (args: {\n forceRefreshToken: boolean;\n }) => Promise<string | null>;\n authProviderLoading: boolean;\n client: IConvexReactClient;\n setIsConvexAuthenticated: React.Dispatch<\n React.SetStateAction<boolean | null>\n >;\n setIsRefreshing: React.Dispatch<React.SetStateAction<boolean>>;\n}) {\n useEffect(() => {\n // If rendered with authProviderAuthenticated=true then clear that auth on in cleanup.\n if (authProviderAuthenticated) {\n return () => {\n client.clearAuth();\n // Set state back to loading in case this is a transition from one\n // fetchToken function to another which signals a new auth context,\n // e.g. a new orgId from Clerk. Auth context changes like this\n // return isAuthenticated: true from useAuth() but if\n // useAuth reports isAuthenticated: false on the next render\n // then this null value will be overridden to false.\n setIsConvexAuthenticated(() => null);\n setIsRefreshing(false);\n };\n }\n }, [\n authProviderAuthenticated,\n fetchAccessToken,\n authProviderLoading,\n client,\n setIsConvexAuthenticated,\n setIsRefreshing,\n ]);\n return null;\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["import_client", "React"]
|
|
7
7
|
}
|
|
@@ -18,6 +18,7 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
18
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
19
|
var actions_impl_exports = {};
|
|
20
20
|
__export(actions_impl_exports, {
|
|
21
|
+
getServiceToken: () => getServiceToken,
|
|
21
22
|
setupActionCalls: () => setupActionCalls
|
|
22
23
|
});
|
|
23
24
|
module.exports = __toCommonJS(actions_impl_exports);
|
|
@@ -26,6 +27,7 @@ var import__ = require("../../index.js");
|
|
|
26
27
|
var import_syscall = require("./syscall.js");
|
|
27
28
|
var import_common = require("../../common/index.js");
|
|
28
29
|
var import_paths = require("../components/paths.js");
|
|
30
|
+
var import_validate = require("./validate.js");
|
|
29
31
|
function syscallArgs(requestId, functionReference, args) {
|
|
30
32
|
const address = (0, import_paths.getFunctionAddress)(functionReference);
|
|
31
33
|
return {
|
|
@@ -60,4 +62,14 @@ function setupActionCalls(requestId) {
|
|
|
60
62
|
}
|
|
61
63
|
};
|
|
62
64
|
}
|
|
65
|
+
async function getServiceToken(service) {
|
|
66
|
+
(0, import_validate.validateArg)(service, 1, "getServiceToken", "service");
|
|
67
|
+
if (service !== "ai-gateway") {
|
|
68
|
+
throw new Error(`Unsupported service "${String(service)}"`);
|
|
69
|
+
}
|
|
70
|
+
return await (0, import_syscall.performAsyncSyscall)("1.0/createServiceToken", {
|
|
71
|
+
service,
|
|
72
|
+
version: import__.version
|
|
73
|
+
});
|
|
74
|
+
}
|
|
63
75
|
//# sourceMappingURL=actions_impl.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/server/impl/actions_impl.ts"],
|
|
4
|
-
"sourcesContent": ["import { convexToJson, jsonToConvex, Value } from \"../../values/index.js\";\nimport { version } from \"../../index.js\";\nimport { performAsyncSyscall } from \"./syscall.js\";\nimport { parseArgs } from \"../../common/index.js\";\nimport { FunctionReference } from \"../../server/api.js\";\nimport { getFunctionAddress } from \"../components/paths.js\";\n\nfunction syscallArgs(\n requestId: string,\n functionReference: any,\n args?: Record<string, Value>,\n) {\n const address = getFunctionAddress(functionReference);\n return {\n ...address,\n args: convexToJson(parseArgs(args)),\n version,\n requestId,\n };\n}\n\nexport function setupActionCalls(requestId: string) {\n return {\n runQuery: async (\n query: FunctionReference<\"query\", \"public\" | \"internal\">,\n args?: Record<string, Value>,\n ): Promise<any> => {\n const result = await performAsyncSyscall(\n \"1.0/actions/query\",\n syscallArgs(requestId, query, args),\n );\n return jsonToConvex(result);\n },\n runMutation: async (\n mutation: FunctionReference<\"mutation\", \"public\" | \"internal\">,\n args?: Record<string, Value>,\n ): Promise<any> => {\n const result = await performAsyncSyscall(\n \"1.0/actions/mutation\",\n syscallArgs(requestId, mutation, args),\n );\n return jsonToConvex(result);\n },\n runAction: async (\n action: FunctionReference<\"action\", \"public\" | \"internal\">,\n args?: Record<string, Value>,\n ): Promise<any> => {\n const result = await performAsyncSyscall(\n \"1.0/actions/action\",\n syscallArgs(requestId, action, args),\n );\n return jsonToConvex(result);\n },\n };\n}\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAAkD;AAClD,eAAwB;AACxB,qBAAoC;AACpC,oBAA0B;AAE1B,mBAAmC;
|
|
4
|
+
"sourcesContent": ["import { convexToJson, jsonToConvex, Value } from \"../../values/index.js\";\nimport { version } from \"../../index.js\";\nimport { performAsyncSyscall } from \"./syscall.js\";\nimport { parseArgs } from \"../../common/index.js\";\nimport { FunctionReference } from \"../../server/api.js\";\nimport { getFunctionAddress } from \"../components/paths.js\";\nimport { validateArg } from \"./validate.js\";\n\nfunction syscallArgs(\n requestId: string,\n functionReference: any,\n args?: Record<string, Value>,\n) {\n const address = getFunctionAddress(functionReference);\n return {\n ...address,\n args: convexToJson(parseArgs(args)),\n version,\n requestId,\n };\n}\n\nexport function setupActionCalls(requestId: string) {\n return {\n runQuery: async (\n query: FunctionReference<\"query\", \"public\" | \"internal\">,\n args?: Record<string, Value>,\n ): Promise<any> => {\n const result = await performAsyncSyscall(\n \"1.0/actions/query\",\n syscallArgs(requestId, query, args),\n );\n return jsonToConvex(result);\n },\n runMutation: async (\n mutation: FunctionReference<\"mutation\", \"public\" | \"internal\">,\n args?: Record<string, Value>,\n ): Promise<any> => {\n const result = await performAsyncSyscall(\n \"1.0/actions/mutation\",\n syscallArgs(requestId, mutation, args),\n );\n return jsonToConvex(result);\n },\n runAction: async (\n action: FunctionReference<\"action\", \"public\" | \"internal\">,\n args?: Record<string, Value>,\n ): Promise<any> => {\n const result = await performAsyncSyscall(\n \"1.0/actions/action\",\n syscallArgs(requestId, action, args),\n );\n return jsonToConvex(result);\n },\n };\n}\n\n/**\n * Get a short-lived credential for calling a Convex-managed service.\n *\n * This function can only be called while an action is running. The credential\n * is scoped to the current deployment and should be sent as a bearer token.\n * Repeated calls in the same action reuse one token; a failed mint is not\n * cached, so a later call retries.\n *\n * @param service - The service the credential may access.\n * @internal\n */\nexport async function getServiceToken(service: \"ai-gateway\"): Promise<string> {\n validateArg(service, 1, \"getServiceToken\", \"service\");\n if (service !== \"ai-gateway\") {\n throw new Error(`Unsupported service \"${String(service)}\"`);\n }\n return await performAsyncSyscall(\"1.0/createServiceToken\", {\n service,\n version,\n });\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAAkD;AAClD,eAAwB;AACxB,qBAAoC;AACpC,oBAA0B;AAE1B,mBAAmC;AACnC,sBAA4B;AAE5B,SAAS,YACP,WACA,mBACA,MACA;AACA,QAAM,cAAU,iCAAmB,iBAAiB;AACpD,SAAO;AAAA,IACL,GAAG;AAAA,IACH,UAAM,gCAAa,yBAAU,IAAI,CAAC;AAAA,IAClC;AAAA,IACA;AAAA,EACF;AACF;AAEO,SAAS,iBAAiB,WAAmB;AAClD,SAAO;AAAA,IACL,UAAU,OACR,OACA,SACiB;AACjB,YAAM,SAAS,UAAM;AAAA,QACnB;AAAA,QACA,YAAY,WAAW,OAAO,IAAI;AAAA,MACpC;AACA,iBAAO,4BAAa,MAAM;AAAA,IAC5B;AAAA,IACA,aAAa,OACX,UACA,SACiB;AACjB,YAAM,SAAS,UAAM;AAAA,QACnB;AAAA,QACA,YAAY,WAAW,UAAU,IAAI;AAAA,MACvC;AACA,iBAAO,4BAAa,MAAM;AAAA,IAC5B;AAAA,IACA,WAAW,OACT,QACA,SACiB;AACjB,YAAM,SAAS,UAAM;AAAA,QACnB;AAAA,QACA,YAAY,WAAW,QAAQ,IAAI;AAAA,MACrC;AACA,iBAAO,4BAAa,MAAM;AAAA,IAC5B;AAAA,EACF;AACF;AAaA,eAAsB,gBAAgB,SAAwC;AAC5E,mCAAY,SAAS,GAAG,mBAAmB,SAAS;AACpD,MAAI,YAAY,cAAc;AAC5B,UAAM,IAAI,MAAM,wBAAwB,OAAO,OAAO,CAAC,GAAG;AAAA,EAC5D;AACA,SAAO,UAAM,oCAAoB,0BAA0B;AAAA,IACzD;AAAA,IACA;AAAA,EACF,CAAC;AACH;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/cjs/server/index.js
CHANGED
|
@@ -31,9 +31,11 @@ __export(server_exports, {
|
|
|
31
31
|
defineComponent: () => import_components.defineComponent,
|
|
32
32
|
defineSchema: () => import_schema.defineSchema,
|
|
33
33
|
defineTable: () => import_schema.defineTable,
|
|
34
|
+
docValidator: () => import_schema.docValidator,
|
|
34
35
|
filterApi: () => import_api.filterApi,
|
|
35
36
|
getFunctionAddress: () => import_components3.getFunctionAddress,
|
|
36
37
|
getFunctionName: () => import_api.getFunctionName,
|
|
38
|
+
getServiceToken: () => import_actions_impl.getServiceToken,
|
|
37
39
|
httpActionGeneric: () => import_registration_impl.httpActionGeneric,
|
|
38
40
|
httpRouter: () => import_router.httpRouter,
|
|
39
41
|
internalActionGeneric: () => import_registration_impl.internalActionGeneric,
|
|
@@ -47,6 +49,7 @@ __export(server_exports, {
|
|
|
47
49
|
module.exports = __toCommonJS(server_exports);
|
|
48
50
|
__reExport(server_exports, require("./database.js"), module.exports);
|
|
49
51
|
var import_registration_impl = require("./impl/registration_impl.js");
|
|
52
|
+
var import_actions_impl = require("./impl/actions_impl.js");
|
|
50
53
|
__reExport(server_exports, require("./pagination.js"), module.exports);
|
|
51
54
|
__reExport(server_exports, require("./search_filter_builder.js"), module.exports);
|
|
52
55
|
__reExport(server_exports, require("./storage.js"), module.exports);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/server/index.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Utilities for implementing server-side Convex query and mutation functions.\n *\n * ## Usage\n *\n * ### Code Generation\n *\n * This module is typically used alongside generated server code.\n *\n * To generate the server code, run `npx convex dev` in your Convex project.\n * This will create a `convex/_generated/server.js` file with the following\n * functions, typed for your schema:\n * - [query](https://docs.convex.dev/generated-api/server#query)\n * - [mutation](https://docs.convex.dev/generated-api/server#mutation)\n *\n * If you aren't using TypeScript and code generation, you can use these untyped\n * functions instead:\n * - {@link queryGeneric}\n * - {@link mutationGeneric}\n *\n * ### Example\n *\n * Convex functions are defined by using either the `query` or\n * `mutation` wrappers.\n *\n * Queries receive a `db` that implements the {@link GenericDatabaseReader} interface.\n *\n * ```js\n * import { query } from \"./_generated/server\";\n *\n * export default query({\n * handler: async ({ db }, { arg1, arg2 }) => {\n * // Your (read-only) code here!\n * },\n * });\n * ```\n *\n * If your function needs to write to the database, such as inserting, updating,\n * or deleting documents, use `mutation` instead which provides a `db` that\n * implements the {@link GenericDatabaseWriter} interface.\n *\n * ```js\n * import { mutation } from \"./_generated/server\";\n *\n * export default mutation({\n * handler: async ({ db }, { arg1, arg2 }) => {\n * // Your mutation code here!\n * },\n * });\n * ```\n * @module\n */\n\nexport type {\n Auth,\n AuthConfig,\n AuthProvider,\n UserIdentity,\n UserIdentityAttributes,\n} from \"./authentication.js\";\nexport * from \"./database.js\";\nexport type {\n GenericDocument,\n GenericFieldPaths,\n GenericIndexFields,\n GenericTableIndexes,\n GenericSearchIndexConfig,\n GenericTableSearchIndexes,\n GenericVectorIndexConfig,\n GenericTableVectorIndexes,\n FieldTypeFromFieldPath,\n FieldTypeFromFieldPathInner,\n GenericTableInfo,\n DocumentByInfo,\n FieldPaths,\n Indexes,\n IndexNames,\n NamedIndex,\n SearchIndexes,\n SearchIndexNames,\n NamedSearchIndex,\n VectorIndexes,\n VectorIndexNames,\n NamedVectorIndex,\n GenericDataModel,\n AnyDataModel,\n TableNamesInDataModel,\n NamedTableInfo,\n DocumentByName,\n} from \"./data_model.js\";\n\nexport type {\n Expression,\n ExpressionOrValue,\n FilterBuilder,\n} from \"./filter_builder.js\";\nexport {\n actionGeneric,\n httpActionGeneric,\n mutationGeneric,\n queryGeneric,\n internalActionGeneric,\n internalMutationGeneric,\n internalQueryGeneric,\n} from \"./impl/registration_impl.js\";\nexport type {\n TransactionMetric,\n TransactionMetrics,\n TransactionLimits,\n FunctionMetadata,\n DeploymentMetadata,\n RequestMetadata,\n QueryMeta,\n MutationMeta,\n ActionMeta,\n} from \"./meta.js\";\nexport type { IndexRange, IndexRangeBuilder } from \"./index_range_builder.js\";\nexport * from \"./pagination.js\";\nexport type { OrderedQuery, Query, QueryInitializer } from \"./query.js\";\nexport type {\n AdvancedRunQueryOptions,\n ArgsArray,\n DefaultFunctionArgs,\n FunctionVisibility,\n ActionBuilder,\n MutationBuilder,\n MutationBuilderWithTable,\n QueryBuilder,\n QueryBuilderWithTable,\n HttpActionBuilder,\n GenericActionCtx,\n GenericMutationCtx,\n GenericMutationCtxWithTable,\n GenericQueryCtx,\n GenericQueryCtxWithTable,\n RegisteredAction,\n RegisteredMutation,\n RegisteredQuery,\n PublicHttpAction,\n UnvalidatedFunction,\n ValidatedFunction,\n ReturnValueForOptionalValidator,\n ArgsArrayForOptionalValidator,\n ArgsArrayToObject,\n DefaultArgsForOptionalValidator,\n} from \"./registration.js\";\nexport * from \"./search_filter_builder.js\";\nexport * from \"./storage.js\";\nexport type { Scheduler, SchedulableFunctionReference } from \"./scheduler.js\";\nexport { cronJobs } from \"./cron.js\";\nexport type { CronJob, Crons } from \"./cron.js\";\nexport type {\n SystemFields,\n IdField,\n WithoutSystemFields,\n WithOptionalSystemFields,\n SystemIndexes,\n IndexTiebreakerField,\n} from \"./system_fields.js\";\nexport { httpRouter, HttpRouter, ROUTABLE_HTTP_METHODS } from \"./router.js\";\nexport type {\n RoutableMethod,\n RouteSpec,\n RouteSpecWithPath,\n RouteSpecWithPathPrefix,\n} from \"./router.js\";\nexport {\n anyApi,\n getFunctionName,\n makeFunctionReference,\n filterApi,\n} from \"./api.js\";\nexport type {\n ApiFromModules,\n AnyApi,\n FilterApi,\n FunctionType,\n FunctionReference,\n FunctionArgs,\n OptionalRestArgs,\n PartialApi,\n ArgsAndOptions,\n FunctionReturnType,\n ValidatorTypeToReturnType,\n} from \"./api.js\";\nexport {\n defineApp,\n defineComponent,\n componentsGeneric,\n createFunctionHandle,\n type AnyChildComponents,\n type EnvDefinition,\n type EnvFromDefinition,\n type EnvFromAppDefinition,\n type AppDefinition,\n} from \"./components/index.js\";\n/**\n * @internal\n */\nexport { currentSystemUdfInComponent } from \"./components/index.js\";\nexport { getFunctionAddress } from \"./components/index.js\";\nexport type {\n ComponentDefinition,\n AnyComponents,\n FunctionHandle,\n} from \"./components/index.js\";\n\n/**\n * @internal\n */\nexport type { Index, SearchIndex, VectorIndex } from \"./schema.js\";\n\nexport { log } from \"./log.js\";\nexport type { AuditLogBody, AuditLogValue } from \"./audit_logging.js\";\n\nexport type {\n SearchIndexConfig,\n VectorIndexConfig,\n TableDefinition,\n SchemaDefinition,\n DefineSchemaOptions,\n GenericSchema,\n DataModelFromSchemaDefinition,\n SystemDataModel,\n SystemTableNames,\n} from \"./schema.js\";\nexport { defineTable, defineSchema } from \"./schema.js\";\n\nexport type {\n VectorSearch,\n VectorSearchQuery,\n VectorFilterBuilder,\n FilterExpression,\n} from \"./vector_search.js\";\n\n/**\n * @public\n */\nexport type { BetterOmit, Expand } from \"../type_utils.js\";\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA4DA,2BAAc,0BA5Dd;AAgGA,+BAQO;
|
|
4
|
+
"sourcesContent": ["/**\n * Utilities for implementing server-side Convex query and mutation functions.\n *\n * ## Usage\n *\n * ### Code Generation\n *\n * This module is typically used alongside generated server code.\n *\n * To generate the server code, run `npx convex dev` in your Convex project.\n * This will create a `convex/_generated/server.js` file with the following\n * functions, typed for your schema:\n * - [query](https://docs.convex.dev/generated-api/server#query)\n * - [mutation](https://docs.convex.dev/generated-api/server#mutation)\n *\n * If you aren't using TypeScript and code generation, you can use these untyped\n * functions instead:\n * - {@link queryGeneric}\n * - {@link mutationGeneric}\n *\n * ### Example\n *\n * Convex functions are defined by using either the `query` or\n * `mutation` wrappers.\n *\n * Queries receive a `db` that implements the {@link GenericDatabaseReader} interface.\n *\n * ```js\n * import { query } from \"./_generated/server\";\n *\n * export default query({\n * handler: async ({ db }, { arg1, arg2 }) => {\n * // Your (read-only) code here!\n * },\n * });\n * ```\n *\n * If your function needs to write to the database, such as inserting, updating,\n * or deleting documents, use `mutation` instead which provides a `db` that\n * implements the {@link GenericDatabaseWriter} interface.\n *\n * ```js\n * import { mutation } from \"./_generated/server\";\n *\n * export default mutation({\n * handler: async ({ db }, { arg1, arg2 }) => {\n * // Your mutation code here!\n * },\n * });\n * ```\n * @module\n */\n\nexport type {\n Auth,\n AuthConfig,\n AuthProvider,\n UserIdentity,\n UserIdentityAttributes,\n} from \"./authentication.js\";\nexport * from \"./database.js\";\nexport type {\n GenericDocument,\n GenericFieldPaths,\n GenericIndexFields,\n GenericTableIndexes,\n GenericSearchIndexConfig,\n GenericTableSearchIndexes,\n GenericVectorIndexConfig,\n GenericTableVectorIndexes,\n FieldTypeFromFieldPath,\n FieldTypeFromFieldPathInner,\n GenericTableInfo,\n DocumentByInfo,\n FieldPaths,\n Indexes,\n IndexNames,\n NamedIndex,\n SearchIndexes,\n SearchIndexNames,\n NamedSearchIndex,\n VectorIndexes,\n VectorIndexNames,\n NamedVectorIndex,\n GenericDataModel,\n AnyDataModel,\n TableNamesInDataModel,\n NamedTableInfo,\n DocumentByName,\n} from \"./data_model.js\";\n\nexport type {\n Expression,\n ExpressionOrValue,\n FilterBuilder,\n} from \"./filter_builder.js\";\nexport {\n actionGeneric,\n httpActionGeneric,\n mutationGeneric,\n queryGeneric,\n internalActionGeneric,\n internalMutationGeneric,\n internalQueryGeneric,\n} from \"./impl/registration_impl.js\";\n/**\n * @internal\n */\nexport { getServiceToken } from \"./impl/actions_impl.js\";\nexport type {\n TransactionMetric,\n TransactionMetrics,\n TransactionLimits,\n FunctionMetadata,\n DeploymentMetadata,\n RequestMetadata,\n QueryMeta,\n MutationMeta,\n ActionMeta,\n} from \"./meta.js\";\nexport type { IndexRange, IndexRangeBuilder } from \"./index_range_builder.js\";\nexport * from \"./pagination.js\";\nexport type { OrderedQuery, Query, QueryInitializer } from \"./query.js\";\nexport type {\n AdvancedRunQueryOptions,\n ArgsArray,\n DefaultFunctionArgs,\n FunctionVisibility,\n ActionBuilder,\n MutationBuilder,\n MutationBuilderWithTable,\n QueryBuilder,\n QueryBuilderWithTable,\n HttpActionBuilder,\n GenericActionCtx,\n GenericMutationCtx,\n GenericMutationCtxWithTable,\n GenericQueryCtx,\n GenericQueryCtxWithTable,\n RegisteredAction,\n RegisteredMutation,\n RegisteredQuery,\n PublicHttpAction,\n UnvalidatedFunction,\n ValidatedFunction,\n ReturnValueForOptionalValidator,\n ArgsArrayForOptionalValidator,\n ArgsArrayToObject,\n DefaultArgsForOptionalValidator,\n} from \"./registration.js\";\nexport * from \"./search_filter_builder.js\";\nexport * from \"./storage.js\";\nexport type { Scheduler, SchedulableFunctionReference } from \"./scheduler.js\";\nexport { cronJobs } from \"./cron.js\";\nexport type { CronJob, Crons } from \"./cron.js\";\nexport type {\n SystemFields,\n IdField,\n WithoutSystemFields,\n WithOptionalSystemFields,\n SystemIndexes,\n IndexTiebreakerField,\n} from \"./system_fields.js\";\nexport { httpRouter, HttpRouter, ROUTABLE_HTTP_METHODS } from \"./router.js\";\nexport type {\n RoutableMethod,\n RouteSpec,\n RouteSpecWithPath,\n RouteSpecWithPathPrefix,\n} from \"./router.js\";\nexport {\n anyApi,\n getFunctionName,\n makeFunctionReference,\n filterApi,\n} from \"./api.js\";\nexport type {\n ApiFromModules,\n AnyApi,\n FilterApi,\n FunctionType,\n FunctionReference,\n FunctionArgs,\n OptionalRestArgs,\n PartialApi,\n ArgsAndOptions,\n FunctionReturnType,\n ValidatorTypeToReturnType,\n} from \"./api.js\";\nexport {\n defineApp,\n defineComponent,\n componentsGeneric,\n createFunctionHandle,\n type AnyChildComponents,\n type EnvDefinition,\n type EnvFromDefinition,\n type EnvFromAppDefinition,\n type AppDefinition,\n} from \"./components/index.js\";\n/**\n * @internal\n */\nexport { currentSystemUdfInComponent } from \"./components/index.js\";\nexport { getFunctionAddress } from \"./components/index.js\";\nexport type {\n ComponentDefinition,\n AnyComponents,\n FunctionHandle,\n} from \"./components/index.js\";\n\n/**\n * @internal\n */\nexport type { Index, SearchIndex, VectorIndex } from \"./schema.js\";\n\nexport { log } from \"./log.js\";\nexport type { AuditLogBody, AuditLogValue } from \"./audit_logging.js\";\n\nexport type {\n SearchIndexConfig,\n VectorIndexConfig,\n TableDefinition,\n SchemaDefinition,\n DefineSchemaOptions,\n GenericSchema,\n DataModelFromSchemaDefinition,\n SystemDataModel,\n SystemTableNames,\n DocValidator,\n SystemFieldValidators,\n} from \"./schema.js\";\nexport { defineTable, defineSchema, docValidator } from \"./schema.js\";\n\nexport type {\n VectorSearch,\n VectorSearchQuery,\n VectorFilterBuilder,\n FilterExpression,\n} from \"./vector_search.js\";\n\n/**\n * @public\n */\nexport type { BetterOmit, Expand } from \"../type_utils.js\";\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA4DA,2BAAc,0BA5Dd;AAgGA,+BAQO;AAIP,0BAAgC;AAahC,2BAAc,4BAzHd;AAsJA,2BAAc,uCAtJd;AAuJA,2BAAc,yBAvJd;AAyJA,kBAAyB;AAUzB,oBAA8D;AAO9D,iBAKO;AAcP,wBAUO;AAIP,IAAAA,qBAA4C;AAC5C,IAAAA,qBAAmC;AAYnC,iBAAoB;AAgBpB,oBAAwD;",
|
|
6
6
|
"names": ["import_components"]
|
|
7
7
|
}
|
|
@@ -23,7 +23,8 @@ __export(schema_exports, {
|
|
|
23
23
|
SchemaDefinition: () => SchemaDefinition,
|
|
24
24
|
TableDefinition: () => TableDefinition,
|
|
25
25
|
defineSchema: () => defineSchema,
|
|
26
|
-
defineTable: () => defineTable
|
|
26
|
+
defineTable: () => defineTable,
|
|
27
|
+
docValidator: () => docValidator
|
|
27
28
|
});
|
|
28
29
|
module.exports = __toCommonJS(schema_exports);
|
|
29
30
|
var import_validator = require("../values/validator.js");
|
|
@@ -149,6 +150,42 @@ function defineTable(documentSchema) {
|
|
|
149
150
|
return new TableDefinition(import_validator.v.object(documentSchema));
|
|
150
151
|
}
|
|
151
152
|
}
|
|
153
|
+
function addSystemFields(tableName, validator) {
|
|
154
|
+
switch (validator.kind) {
|
|
155
|
+
case "object":
|
|
156
|
+
return validator.extend({
|
|
157
|
+
_id: import_validator.v.id(tableName),
|
|
158
|
+
_creationTime: import_validator.v.number()
|
|
159
|
+
});
|
|
160
|
+
case "union":
|
|
161
|
+
return import_validator.v.union(
|
|
162
|
+
...validator.members.map(
|
|
163
|
+
(member) => addSystemFields(tableName, member)
|
|
164
|
+
)
|
|
165
|
+
);
|
|
166
|
+
// `v.any()` already permits the system fields.
|
|
167
|
+
case "any":
|
|
168
|
+
return validator;
|
|
169
|
+
default:
|
|
170
|
+
throw new Error(
|
|
171
|
+
`Invalid validator for table "${tableName}": a table's documents must be objects, or a union of objects (see https://docs.convex.dev/database/schemas)`
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
function docValidator(tableName, table) {
|
|
176
|
+
return addSystemFields(tableName, table.validator);
|
|
177
|
+
}
|
|
178
|
+
function tableInSchema(schema, tableName) {
|
|
179
|
+
const table = schema.tables[tableName];
|
|
180
|
+
if (table === void 0) {
|
|
181
|
+
throw new Error(
|
|
182
|
+
`Table "${tableName}" is not in this schema. Tables in this schema: ${Object.keys(
|
|
183
|
+
schema.tables
|
|
184
|
+
).join(", ")}`
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
return table;
|
|
188
|
+
}
|
|
152
189
|
class SchemaDefinition {
|
|
153
190
|
/**
|
|
154
191
|
* @internal
|
|
@@ -160,6 +197,37 @@ class SchemaDefinition {
|
|
|
160
197
|
this.tables = tables;
|
|
161
198
|
this.schemaValidation = options?.schemaValidation === void 0 ? true : options.schemaValidation;
|
|
162
199
|
}
|
|
200
|
+
/**
|
|
201
|
+
* The validator for whole documents of a table in this schema: the table's
|
|
202
|
+
* own validator with the `_id` and `_creationTime` system fields added.
|
|
203
|
+
*
|
|
204
|
+
* @example
|
|
205
|
+
* ```ts
|
|
206
|
+
* export const get = query({
|
|
207
|
+
* args: { id: schema.id("messages") },
|
|
208
|
+
* returns: v.union(schema.doc("messages"), v.null()),
|
|
209
|
+
* handler: (ctx, args) => ctx.db.get(args.id),
|
|
210
|
+
* });
|
|
211
|
+
* ```
|
|
212
|
+
*
|
|
213
|
+
* @param tableName - The name of a table in this schema.
|
|
214
|
+
* @returns A validator matching documents of that table.
|
|
215
|
+
*/
|
|
216
|
+
doc(tableName) {
|
|
217
|
+
return docValidator(tableName, tableInSchema(this, tableName));
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* The validator for IDs of a table in this schema.
|
|
221
|
+
*
|
|
222
|
+
* Same as `v.id(tableName)`, but only accepts tables in this schema.
|
|
223
|
+
*
|
|
224
|
+
* @param tableName - The name of a table in this schema.
|
|
225
|
+
* @returns A validator matching IDs of that table.
|
|
226
|
+
*/
|
|
227
|
+
id(tableName) {
|
|
228
|
+
tableInSchema(this, tableName);
|
|
229
|
+
return import_validator.v.id(tableName);
|
|
230
|
+
}
|
|
163
231
|
/**
|
|
164
232
|
* Export the contents of this definition.
|
|
165
233
|
*
|