Declare typed Convex env and route auth through @code/env/convex
- Register SITE_URL, NATIVE_APP_URL, CONVEX_SITE_URL, FLUE_DB_TOKEN in convex.config.ts so the generated server.js exposes a typed env object. - Rewrite auth.ts to consume @code/env/convex and tighten the getCurrentUser handler. - Refresh the backend README to describe the control-plane role and generated-file policy.
This commit is contained in:
@@ -1,88 +1,16 @@
|
||||
# Welcome to your Convex functions directory!
|
||||
# Convex Backend
|
||||
|
||||
Write your Convex functions here.
|
||||
See https://docs.convex.dev/functions for more.
|
||||
This directory contains the Convex control plane for the app and daemon runtime. Generated files under `_generated/` are maintained by Convex and should not be edited by hand.
|
||||
|
||||
A query function that takes two arguments looks like:
|
||||
## Daemon Control Plane
|
||||
|
||||
```ts
|
||||
// convex/myFunctions.ts
|
||||
import { query } from "./_generated/server";
|
||||
import { v } from "convex/values";
|
||||
- `schema.ts` defines daemon definitions, high-churn daemon presence, leased daemon commands, append-only command events, and the sample `todos` table.
|
||||
- `daemons.ts` manages stable daemon definitions with `upsert`, `get`, and `list`.
|
||||
- `daemonRuntime.ts` records daemon session lifecycle: `connect`, `heartbeat`, `disconnect`, `recordEvent`, and bounded event listing.
|
||||
- `daemonCommands.ts` owns the command queue: `enqueue`, `available`, `claim`, `start`, `succeed`, `fail`, `cancel`, and bounded command listing.
|
||||
|
||||
export const myQueryFunction = query({
|
||||
// Validators for arguments.
|
||||
args: {
|
||||
first: v.number(),
|
||||
second: v.string(),
|
||||
},
|
||||
Commands are claimed by daemon session. Preserve the `claimedBySessionId` ownership checks, `leaseExpiresAt` expiry semantics, terminal statuses, and bounded query results when changing this flow.
|
||||
|
||||
// Function implementation.
|
||||
handler: async (ctx, args) => {
|
||||
// Read the database as many times as you need here.
|
||||
// See https://docs.convex.dev/database/reading-data.
|
||||
const documents = await ctx.db.query("tablename").collect();
|
||||
## Usage
|
||||
|
||||
// Arguments passed from the client are properties of the args object.
|
||||
console.log(args.first, args.second);
|
||||
|
||||
// Write arbitrary JavaScript here: filter, aggregate, build derived data,
|
||||
// remove non-public properties, or create new objects.
|
||||
return documents;
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
Using this query function in a React component looks like:
|
||||
|
||||
```ts
|
||||
const data = useQuery(api.myFunctions.myQueryFunction, {
|
||||
first: 10,
|
||||
second: "hello",
|
||||
});
|
||||
```
|
||||
|
||||
A mutation function looks like:
|
||||
|
||||
```ts
|
||||
// convex/myFunctions.ts
|
||||
import { mutation } from "./_generated/server";
|
||||
import { v } from "convex/values";
|
||||
|
||||
export const myMutationFunction = mutation({
|
||||
// Validators for arguments.
|
||||
args: {
|
||||
first: v.string(),
|
||||
second: v.string(),
|
||||
},
|
||||
|
||||
// Function implementation.
|
||||
handler: async (ctx, args) => {
|
||||
// Insert or modify documents in the database here.
|
||||
// Mutations can also read from the database like queries.
|
||||
// See https://docs.convex.dev/database/writing-data.
|
||||
const message = { body: args.first, author: args.second };
|
||||
const id = await ctx.db.insert("messages", message);
|
||||
|
||||
// Optionally, return a value from your mutation.
|
||||
return await ctx.db.get("messages", id);
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
Using this mutation function in a React component looks like:
|
||||
|
||||
```ts
|
||||
const mutation = useMutation(api.myFunctions.myMutationFunction);
|
||||
function handleButtonPress() {
|
||||
// fire and forget, the most common way to use mutations
|
||||
mutation({ first: "Hello!", second: "me" });
|
||||
// OR
|
||||
// use the result once the mutation has completed
|
||||
mutation({ first: "Hello!", second: "me" }).then((result) => console.log(result));
|
||||
}
|
||||
```
|
||||
|
||||
Use the Convex CLI to push your functions to a deployment. See everything
|
||||
the Convex CLI can do by running `npx convex -h` in your project root
|
||||
directory. To learn more, launch the docs with `npx convex docs`.
|
||||
Convex functions are exposed by file path through the generated `api` object, for example `api.daemonCommands.enqueue` or `api.daemonRuntime.connect`. Run `bun run dev:server` from the repository root to start the development deployment, and `bun run dev:setup` when configuring Convex for the first time.
|
||||
|
||||
2
packages/backend/convex/_generated/api.d.ts
vendored
2
packages/backend/convex/_generated/api.d.ts
vendored
@@ -12,6 +12,7 @@ import type * as auth from "../auth.js";
|
||||
import type * as daemonCommands from "../daemonCommands.js";
|
||||
import type * as daemonRuntime from "../daemonRuntime.js";
|
||||
import type * as daemons from "../daemons.js";
|
||||
import type * as fluePersistence from "../fluePersistence.js";
|
||||
import type * as healthCheck from "../healthCheck.js";
|
||||
import type * as http from "../http.js";
|
||||
import type * as privateData from "../privateData.js";
|
||||
@@ -28,6 +29,7 @@ declare const fullApi: ApiFromModules<{
|
||||
daemonCommands: typeof daemonCommands;
|
||||
daemonRuntime: typeof daemonRuntime;
|
||||
daemons: typeof daemons;
|
||||
fluePersistence: typeof fluePersistence;
|
||||
healthCheck: typeof healthCheck;
|
||||
http: typeof http;
|
||||
privateData: typeof privateData;
|
||||
|
||||
14
packages/backend/convex/_generated/server.d.ts
vendored
14
packages/backend/convex/_generated/server.d.ts
vendored
@@ -21,6 +21,15 @@ import {
|
||||
} from "convex/server";
|
||||
import type { DataModel } from "./dataModel.js";
|
||||
|
||||
/**
|
||||
* Typesafe environment variables declared in `convex.config.ts`.
|
||||
*/
|
||||
type Env = {
|
||||
readonly FLUE_DB_TOKEN: string;
|
||||
readonly NATIVE_APP_URL: string | undefined;
|
||||
readonly SITE_URL: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Define a query in this Convex app's public API.
|
||||
*
|
||||
@@ -95,6 +104,11 @@ export declare const internalAction: ActionBuilder<DataModel, "internal">;
|
||||
*/
|
||||
export declare const httpAction: HttpActionBuilder;
|
||||
|
||||
/**
|
||||
* Typesafe environment variables declared in `convex.config.ts`.
|
||||
*/
|
||||
export declare const env: Env;
|
||||
|
||||
/**
|
||||
* A set of services for use within Convex query functions.
|
||||
*
|
||||
|
||||
@@ -91,3 +91,8 @@ export const internalAction = internalActionGeneric;
|
||||
* @returns The wrapped function. Import this function from `convex/http.js` and route it to hook it up.
|
||||
*/
|
||||
export const httpAction = httpActionGeneric;
|
||||
|
||||
/**
|
||||
* Typesafe environment variables declared in `convex.config.ts`.
|
||||
*/
|
||||
export const env = process.env;
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { expo } from "@better-auth/expo";
|
||||
import { createClient, type GenericCtx } from "@convex-dev/better-auth";
|
||||
import { env } from "@code/env/convex";
|
||||
import { createClient } from "@convex-dev/better-auth";
|
||||
import type { GenericCtx } from "@convex-dev/better-auth";
|
||||
import { convex, crossDomain } from "@convex-dev/better-auth/plugins";
|
||||
import { betterAuth } from "better-auth/minimal";
|
||||
|
||||
@@ -8,15 +10,14 @@ import type { DataModel } from "./_generated/dataModel";
|
||||
import { query } from "./_generated/server";
|
||||
import authConfig from "./auth.config";
|
||||
|
||||
const siteUrl = process.env.SITE_URL!;
|
||||
const nativeAppUrl = process.env.NATIVE_APP_URL || "code://";
|
||||
const siteUrl = env.SITE_URL;
|
||||
const nativeAppUrl = env.NATIVE_APP_URL ?? "code://";
|
||||
|
||||
export const authComponent = createClient<DataModel>(components.betterAuth);
|
||||
|
||||
function createAuth(ctx: GenericCtx<DataModel>) {
|
||||
return betterAuth({
|
||||
baseURL: process.env.CONVEX_SITE_URL,
|
||||
trustedOrigins: [siteUrl, nativeAppUrl, "exp://"],
|
||||
const createAuth = (ctx: GenericCtx<DataModel>) =>
|
||||
betterAuth({
|
||||
baseURL: env.CONVEX_SITE_URL,
|
||||
database: authComponent.adapter(ctx),
|
||||
emailAndPassword: {
|
||||
enabled: true,
|
||||
@@ -30,14 +31,12 @@ function createAuth(ctx: GenericCtx<DataModel>) {
|
||||
jwksRotateOnTokenGenerationError: true,
|
||||
}),
|
||||
],
|
||||
trustedOrigins: [siteUrl, nativeAppUrl, "exp://"],
|
||||
});
|
||||
}
|
||||
|
||||
export { createAuth };
|
||||
|
||||
export const getCurrentUser = query({
|
||||
args: {},
|
||||
handler: async (ctx) => {
|
||||
return await authComponent.safeGetAuthUser(ctx);
|
||||
},
|
||||
handler: (ctx) => authComponent.safeGetAuthUser(ctx),
|
||||
});
|
||||
|
||||
@@ -1,7 +1,14 @@
|
||||
import betterAuth from "@convex-dev/better-auth/convex.config";
|
||||
import { defineApp } from "convex/server";
|
||||
import { v } from "convex/values";
|
||||
|
||||
const app = defineApp();
|
||||
const app = defineApp({
|
||||
env: {
|
||||
NATIVE_APP_URL: v.optional(v.string()),
|
||||
SITE_URL: v.string(),
|
||||
FLUE_DB_TOKEN: v.string(),
|
||||
},
|
||||
});
|
||||
app.use(betterAuth);
|
||||
|
||||
export default app;
|
||||
|
||||
Reference in New Issue
Block a user