Skip to content

Commit d0e9d08

Browse files
committed
feat: dynamic Convex integration 🔥🔥
1 parent cbaab7e commit d0e9d08

28 files changed

Lines changed: 1011 additions & 13 deletions

README.md

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
* [Apps and Libraries](#apps-and-libraries)
1717
* [`frontend`: a Nuxt app, compatible with v4 structure.](#frontend-a-nuxt-app-compatible-with-v4-structure)
1818
* [`backend`: a Hono🔥 app.](#backend-a-hono-app)
19+
* [`backend-convex`: a Convex app.](#backend-convex-a-convex-app)
1920
* [Local packages](#local-packages)
2021
* [Utilities](#utilities)
2122
* [Build](#build)
@@ -58,14 +59,18 @@ So if you use SSR, you could use the official [Nuxt Kinde](https://nuxt.com/modu
5859

5960
### Apps and Libraries
6061

61-
#### [`frontend`](./apps/frontend/README.md): a [Nuxt](https://nuxt.com/) app, compatible with v4 structure.
62-
+ By default, the frontend `/api/*` routes is proxied to the `backendUrl`.
63-
+ The `rpcApi` plugin will call the `/api/*` proxy if they're on the same domain but different ports (e.g: 127.0.0.1)
64-
+ > this mimics a production environment where the static frontend and the backend lives on the same domain at /api, which is the most efficient configuration for Cloudfront + Lambda Function Url, or Cloudflare Workers.
65-
+ If the `frontend` and `backend` are on different domains then the backend will be called directly without proxy.
66-
+ This could be configured in frontend's [`app.config.ts`](./apps/frontend/app/app.config.ts)
62+
#### [`frontend`](./apps/frontend): a [Nuxt](https://nuxt.com/) app, compatible with v4 structure.
63+
* By default, the frontend `/api/*` routes is proxied to the `backendUrl`.
64+
* The `rpcApi` plugin will call the `/api/*` proxy if they're on the same domain but different ports (e.g: 127.0.0.1)
65+
* > this mimics a production environment where the static frontend and the backend lives on the same domain at /api, which is the most efficient configuration for Cloudfront + Lambda Function Url, or Cloudflare Workers.
66+
* If the `frontend` and `backend` are on different domains then the backend will be called directly without proxy.
67+
* This could be configured in frontend's [`app.config.ts`](./apps/frontend/app/app.config.ts)
6768

68-
#### [`backend`](./apps/backend/README.md): a [Hono🔥](https://hono.dev/) app.
69+
#### [`backend`](./apps/backend): a [Hono🔥](https://hono.dev/) app.
70+
71+
#### [`backend-convex`](./apps/backend-convex): a [Convex](https://convex.dev/) app.
72+
* By default, the Convex app is not enabled in development, to enable it, change the root `dev` script from `dev:noConvex` to `dev:full`.
73+
* To deploy with Convex in production, simply run the `deploy` script of `backend-convex` app, then, set your Convex's production url to `NUXT_PUBLIC_CONVEX_URL` env in `frontend`'s `.env.prod` file or CI / build machine env variable.
6974

7075
### Local packages
7176

apps/backend-convex/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
.env.local

apps/backend-convex/README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# backend-convex
2+
3+
**backend-convex** is an additional backend for the project, powered by [Convex](https://convex.dev).
4+
5+
Convex helps you kick-start amazing apps super fast and simple.

apps/backend-convex/_util.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { parseEnvFile } from '@local/common/src/utils/env'
2+
import { objectPick } from '@namesmt/utils'
3+
import { resolve } from 'pathe'
4+
5+
export async function getConvexEnvs() {
6+
return objectPick(
7+
await parseEnvFile(resolve(import.meta.dirname, '.env.local')).catch(() => ({} as any)),
8+
['CONVEX_DEPLOYMENT', 'CONVEX_URL'],
9+
)
10+
}
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
# Welcome to your Convex functions directory!
2+
3+
Write your Convex functions here.
4+
See https://docs.convex.dev/functions for more.
5+
6+
A query function that takes two arguments looks like:
7+
8+
```ts
9+
import { v } from 'convex/values'
10+
// functions.js
11+
import { query } from './_generated/server'
12+
13+
export const myQueryFunction = query({
14+
// Validators for arguments.
15+
args: {
16+
first: v.number(),
17+
second: v.string(),
18+
},
19+
20+
// Function implementation.
21+
handler: async (ctx, args) => {
22+
// Read the database as many times as you need here.
23+
// See https://docs.convex.dev/database/reading-data.
24+
const documents = await ctx.db.query('tablename').collect()
25+
26+
// Arguments passed from the client are properties of the args object.
27+
console.log(args.first, args.second)
28+
29+
// Write arbitrary JavaScript here: filter, aggregate, build derived data,
30+
// remove non-public properties, or create new objects.
31+
return documents
32+
},
33+
})
34+
```
35+
36+
Using this query function in a React component looks like:
37+
38+
```ts
39+
const data = useQuery(api.functions.myQueryFunction, {
40+
first: 10,
41+
second: 'hello',
42+
})
43+
```
44+
45+
A mutation function looks like:
46+
47+
```ts
48+
import { v } from 'convex/values'
49+
// functions.js
50+
import { mutation } from './_generated/server'
51+
52+
export const myMutationFunction = mutation({
53+
// Validators for arguments.
54+
args: {
55+
first: v.string(),
56+
second: v.string(),
57+
},
58+
59+
// Function implementation.
60+
handler: async (ctx, args) => {
61+
// Insert or modify documents in the database here.
62+
// Mutations can also read from the database like queries.
63+
// See https://docs.convex.dev/database/writing-data.
64+
const message = { body: args.first, author: args.second }
65+
const id = await ctx.db.insert('messages', message)
66+
67+
// Optionally, return a value from your mutation.
68+
return await ctx.db.get(id)
69+
},
70+
})
71+
```
72+
73+
Using this mutation function in a React component looks like:
74+
75+
```ts
76+
const mutation = useMutation(api.functions.myMutationFunction)
77+
function handleButtonPress() {
78+
// fire and forget, the most common way to use mutations
79+
mutation({ first: 'Hello!', second: 'me' })
80+
// OR
81+
// use the result once the mutation has completed
82+
mutation({ first: 'Hello!', second: 'me' }).then(result =>
83+
console.log(result),
84+
)
85+
}
86+
```
87+
88+
Use the Convex CLI to push your functions to a deployment. See everything
89+
the Convex CLI can do by running `npx convex -h` in your project root
90+
directory. To learn more, launch the docs with `npx convex docs`.
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/* eslint-disable */
2+
/**
3+
* Generated `api` utility.
4+
*
5+
* THIS CODE IS AUTOMATICALLY GENERATED.
6+
*
7+
* To regenerate, run `npx convex dev`.
8+
* @module
9+
*/
10+
11+
import type {
12+
ApiFromModules,
13+
FilterApi,
14+
FunctionReference,
15+
} from "convex/server";
16+
import type * as tasks from "../tasks.js";
17+
18+
/**
19+
* A utility for referencing Convex functions in your app's API.
20+
*
21+
* Usage:
22+
* ```js
23+
* const myFunctionReference = api.myModule.myFunction;
24+
* ```
25+
*/
26+
declare const fullApi: ApiFromModules<{
27+
tasks: typeof tasks;
28+
}>;
29+
export declare const api: FilterApi<
30+
typeof fullApi,
31+
FunctionReference<any, "public">
32+
>;
33+
export declare const internal: FilterApi<
34+
typeof fullApi,
35+
FunctionReference<any, "internal">
36+
>;
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/* eslint-disable */
2+
/**
3+
* Generated `api` utility.
4+
*
5+
* THIS CODE IS AUTOMATICALLY GENERATED.
6+
*
7+
* To regenerate, run `npx convex dev`.
8+
* @module
9+
*/
10+
11+
import { anyApi } from "convex/server";
12+
13+
/**
14+
* A utility for referencing Convex functions in your app's API.
15+
*
16+
* Usage:
17+
* ```js
18+
* const myFunctionReference = api.myModule.myFunction;
19+
* ```
20+
*/
21+
export const api = anyApi;
22+
export const internal = anyApi;
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/* eslint-disable */
2+
/**
3+
* Generated data model types.
4+
*
5+
* THIS CODE IS AUTOMATICALLY GENERATED.
6+
*
7+
* To regenerate, run `npx convex dev`.
8+
* @module
9+
*/
10+
11+
import { AnyDataModel } from "convex/server";
12+
import type { GenericId } from "convex/values";
13+
14+
/**
15+
* No `schema.ts` file found!
16+
*
17+
* This generated code has permissive types like `Doc = any` because
18+
* Convex doesn't know your schema. If you'd like more type safety, see
19+
* https://docs.convex.dev/using/schemas for instructions on how to add a
20+
* schema file.
21+
*
22+
* After you change a schema, rerun codegen with `npx convex dev`.
23+
*/
24+
25+
/**
26+
* The names of all of your Convex tables.
27+
*/
28+
export type TableNames = string;
29+
30+
/**
31+
* The type of a document stored in Convex.
32+
*/
33+
export type Doc = any;
34+
35+
/**
36+
* An identifier for a document in Convex.
37+
*
38+
* Convex documents are uniquely identified by their `Id`, which is accessible
39+
* on the `_id` field. To learn more, see [Document IDs](https://docs.convex.dev/using/document-ids).
40+
*
41+
* Documents can be loaded using `db.get(id)` in query and mutation functions.
42+
*
43+
* IDs are just strings at runtime, but this type can be used to distinguish them from other
44+
* strings when type checking.
45+
*/
46+
export type Id<TableName extends TableNames = TableNames> =
47+
GenericId<TableName>;
48+
49+
/**
50+
* A type describing your Convex data model.
51+
*
52+
* This type includes information about what tables you have, the type of
53+
* documents stored in those tables, and the indexes defined on them.
54+
*
55+
* This type is used to parameterize methods like `queryGeneric` and
56+
* `mutationGeneric` to make them type-safe.
57+
*/
58+
export type DataModel = AnyDataModel;

0 commit comments

Comments
 (0)