ConusAI vendor v0.1.0-dev.20261027+9b1131fb
ci / gate (push) Waiting to run

This commit is contained in:
ConusAI vendor v0.1.0-dev.20261027+9b1131fb
2026-10-27 18:05:17 +00:00
commit 3102273ec7
538 changed files with 80203 additions and 0 deletions
+7
View File
@@ -0,0 +1,7 @@
// SPDX-License-Identifier: LicenseRef-ConusAI-Template-1.0
// The one token issuer this deployment accepts: Better Auth's Convex plugin, on this deployment's own
// site URL. The app server's session validation (conusaiAuth.ts) runs under such a token.
import { getAuthConfigProvider } from "@convex-dev/better-auth/auth-config"
import type { AuthConfig } from "convex/server"
export default { providers: [getAuthConfigProvider()] } satisfies AuthConfig
+37
View File
@@ -0,0 +1,37 @@
// SPDX-License-Identifier: LicenseRef-ConusAI-Template-1.0
// Better Auth for this app, on Convex. SITE_URL is the app's public origin (CONUSAI_PUBLIC_URL), the
// only origin Better Auth trusts; BETTER_AUTH_SECRET signs its cookies and tokens. Both are this
// deployment's environment, installed by ../deploy.mjs, and never reach the app's browser bundle.
import { revocationTriggers } from "@conusai-kit/auth-convex-better-auth/convex"
import { type AuthFunctions, createClient, type GenericCtx } from "@convex-dev/better-auth"
import { betterAuth } from "better-auth/minimal"
import { components, internal } from "./_generated/api"
import type { DataModel } from "./_generated/dataModel"
import authConfig from "./auth.config"
import { betterAuthOptions } from "./betterAuth/options"
import authSchema from "./betterAuth/schema"
const authFunctions: AuthFunctions = internal.auth
// The triggers write the revocation outbox in the same mutation that ends a session or an account.
export const authComponent = createClient<DataModel, typeof authSchema>(components.betterAuth, {
authFunctions,
triggers: revocationTriggers(),
local: { schema: authSchema },
})
export const { onCreate, onUpdate, onDelete } = authComponent.triggersApi()
export const createAuthOptions = (ctx: GenericCtx<DataModel>) => {
const siteUrl = process.env.SITE_URL
return {
...(siteUrl ? { baseURL: siteUrl, trustedOrigins: [siteUrl] } : {}),
database: authComponent.adapter(ctx),
...betterAuthOptions(authConfig),
}
}
export const createAuth = (ctx: GenericCtx<DataModel>) => {
if (!process.env.SITE_URL) throw new Error("SITE_URL is not set: deploy.mjs installs the app's public origin")
return betterAuth(createAuthOptions(ctx))
}
@@ -0,0 +1,10 @@
// SPDX-License-Identifier: LicenseRef-ConusAI-Template-1.0
// The component's database functions over the locally installed schema.
import { createApi } from "@convex-dev/better-auth"
import { createAuthOptions } from "../auth"
import schema from "./schema"
export const { create, findOne, findMany, updateOne, updateMany, deleteOne, deleteMany } = createApi(
schema,
createAuthOptions,
)
@@ -0,0 +1,7 @@
// SPDX-License-Identifier: LicenseRef-ConusAI-Template-1.0
// The Better Auth component, installed locally (@convex-dev/better-auth "local install"): its tables
// are ./schema.ts, generated from this app's own Better Auth options (./options.ts).
import { defineComponent } from "convex/server"
const component = defineComponent("betterAuth")
export default component
@@ -0,0 +1,33 @@
// SPDX-License-Identifier: LicenseRef-ConusAI-Template-1.0
// What of this app's Better Auth configuration shapes its tables. ./schema.ts is generated from it
// (test/better-auth.test.ts checks the two agree; `pnpm exec vitest run test/better-auth.test.ts -u`
// regenerates the schema after a change here), and ../auth.ts builds Better Auth with it.
//
// - email and password sign-in, without e-mail verification (an app that sends mail turns it on)
// - the person's own account deletion (`/delete-user`): the revocation relay hands it to the app's
// account flow, which erases the person's data in every module (apps/web/src/server/better-auth.ts)
// - the admin plugin: an administrator disables (`banned`) a user, which ends every session of the
// user and refuses the next sign-in; the session validation refuses a disabled user as well
// - rate limits kept in the deployment's own table, since a Convex function keeps no memory
import { convex } from "@convex-dev/better-auth/plugins"
import type { BetterAuthOptions } from "better-auth/minimal"
import { admin } from "better-auth/plugins/admin"
import type { AuthConfig } from "convex/server"
export const MIN_PASSWORD_LENGTH = 12
/** The administrators the admin plugin accepts, by Better Auth user ID (BETTER_AUTH_ADMIN_USER_IDS, comma-separated). */
const adminUserIds = (): string[] =>
(process.env.BETTER_AUTH_ADMIN_USER_IDS ?? "")
.split(",")
.map((id) => id.trim())
.filter(Boolean)
export function betterAuthOptions(authConfig: AuthConfig) {
return {
emailAndPassword: { enabled: true, requireEmailVerification: false, minPasswordLength: MIN_PASSWORD_LENGTH },
user: { deleteUser: { enabled: true } },
rateLimit: { enabled: true, storage: "database" },
plugins: [convex({ authConfig }), admin({ adminUserIds: adminUserIds() })],
} satisfies Omit<BetterAuthOptions, "database">
}
@@ -0,0 +1,84 @@
// SPDX-License-Identifier: LicenseRef-ConusAI-Template-1.0
// Generated from ./options.ts by the @convex-dev/better-auth schema generator: do not edit it by hand.
// After a change of the Better Auth options, regenerate it with
// pnpm exec vitest run test/better-auth.test.ts -u
// (the "local install" of @convex-dev/better-auth, which is how the admin plugin's fields get here).
import { defineSchema, defineTable } from "convex/server";
import { v } from "convex/values";
export const tables = {
user: defineTable({
name: v.string(),
email: v.string(),
emailVerified: v.boolean(),
image: v.optional(v.union(v.null(), v.string())),
createdAt: v.number(),
updatedAt: v.number(),
userId: v.optional(v.union(v.null(), v.string())),
role: v.optional(v.union(v.null(), v.string())),
banned: v.optional(v.union(v.null(), v.boolean())),
banReason: v.optional(v.union(v.null(), v.string())),
banExpires: v.optional(v.union(v.null(), v.number())),
})
.index("email_name", ["email","name"])
.index("name", ["name"])
.index("userId", ["userId"]),
session: defineTable({
expiresAt: v.number(),
token: v.string(),
createdAt: v.number(),
updatedAt: v.number(),
ipAddress: v.optional(v.union(v.null(), v.string())),
userAgent: v.optional(v.union(v.null(), v.string())),
userId: v.string(),
impersonatedBy: v.optional(v.union(v.null(), v.string())),
})
.index("expiresAt", ["expiresAt"])
.index("expiresAt_userId", ["expiresAt","userId"])
.index("token", ["token"])
.index("userId", ["userId"]),
account: defineTable({
accountId: v.string(),
providerId: v.string(),
userId: v.string(),
accessToken: v.optional(v.union(v.null(), v.string())),
refreshToken: v.optional(v.union(v.null(), v.string())),
idToken: v.optional(v.union(v.null(), v.string())),
accessTokenExpiresAt: v.optional(v.union(v.null(), v.number())),
refreshTokenExpiresAt: v.optional(v.union(v.null(), v.number())),
scope: v.optional(v.union(v.null(), v.string())),
password: v.optional(v.union(v.null(), v.string())),
createdAt: v.number(),
updatedAt: v.number(),
})
.index("accountId", ["accountId"])
.index("accountId_providerId", ["accountId","providerId"])
.index("providerId_userId", ["providerId","userId"])
.index("userId", ["userId"]),
verification: defineTable({
identifier: v.string(),
value: v.string(),
expiresAt: v.number(),
createdAt: v.number(),
updatedAt: v.number(),
})
.index("expiresAt", ["expiresAt"])
.index("identifier", ["identifier"]),
jwks: defineTable({
publicKey: v.string(),
privateKey: v.string(),
createdAt: v.number(),
expiresAt: v.optional(v.union(v.null(), v.number())),
}),
rateLimit: defineTable({
key: v.string(),
count: v.number(),
lastRequest: v.number(),
})
.index("key", ["key"]),
};
const schema = defineSchema(tables);
export default schema;
+31
View File
@@ -0,0 +1,31 @@
// SPDX-License-Identifier: LicenseRef-ConusAI-Template-1.0
// What the app server asks of this deployment (@conusai-kit/auth-convex-better-auth):
//
// validateSession the session check of every request, under the token Better Auth issued for
// the request's own session cookie (public: a token is the only way in)
// pendingRevocations the revocation outbox, drained by the relay with the deployment's admin key
// settleRevocation (internal: only the admin key reaches them)
// endAccount the app's own account deletion ends the person's Better Auth account first
// (internal), through Better Auth itself, so the component triggers record it
import { defineBetterAuthSessionApi } from "@conusai-kit/auth-convex-better-auth/convex"
import { v } from "convex/values"
import { components } from "./_generated/api"
import { internalMutation } from "./_generated/server"
import { authComponent, createAuth } from "./auth"
export const { validateSession, pendingRevocations, settleRevocation } = defineBetterAuthSessionApi({
authComponent,
component: components.betterAuth,
})
export const endAccount = internalMutation({
args: { userId: v.string() },
returns: v.null(),
handler: async (ctx, { userId }) => {
const auth = await createAuth(ctx).$context
if (!(await auth.internalAdapter.findUserById(userId))) return null
// Its sessions, accounts and the user, each through the component, so every trigger records it.
await auth.internalAdapter.deleteUser(userId)
return null
},
})
+10
View File
@@ -0,0 +1,10 @@
// SPDX-License-Identifier: LicenseRef-ConusAI-Template-1.0
// The Better Auth deployment of this app (AUTH_PROVIDER=convex-better-auth, joint contract §14): a
// Convex app of its own whose one component is Better Auth, installed locally (./betterAuth) so its
// schema carries the admin plugin's fields. The app's own data stays where its profile keeps it.
import { defineApp } from "convex/server"
import betterAuth from "./betterAuth/convex.config"
const app = defineApp()
app.use(betterAuth)
export default app
+9
View File
@@ -0,0 +1,9 @@
// SPDX-License-Identifier: LicenseRef-ConusAI-Template-1.0
// Better Auth's routes on this deployment's site URL. A browser never calls them directly: the app's
// same-origin proxy (apps/web/app/api/auth) forwards the few a browser needs.
import { httpRouter } from "convex/server"
import { authComponent, createAuth } from "./auth"
const http = httpRouter()
authComponent.registerRoutes(http, createAuth)
export default http
+8
View File
@@ -0,0 +1,8 @@
// SPDX-License-Identifier: LicenseRef-ConusAI-Template-1.0
// This deployment's own table: the revocation outbox the component triggers write and the app
// server's relay drains (@conusai-kit/auth-convex-better-auth). Better Auth's tables are the
// component's (./betterAuth/schema.ts).
import { revocationTables } from "@conusai-kit/auth-convex-better-auth/convex"
import { defineSchema } from "convex/server"
export default defineSchema({ ...revocationTables })
+13
View File
@@ -0,0 +1,13 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"module": "ESNext",
"moduleResolution": "Bundler",
"noEmit": true,
"types": ["node"],
"exactOptionalPropertyTypes": false,
"noUnusedLocals": true
},
"include": ["./**/*.ts"],
"exclude": ["./_generated"]
}