feat: add zero
This commit is contained in:
25
api/src/auth.ts
Normal file
25
api/src/auth.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { betterAuth } from "better-auth";
|
||||
import { genericOAuth } from "better-auth/plugins";
|
||||
import { expo } from "@better-auth/expo";
|
||||
import { Pool } from "pg";
|
||||
|
||||
export const auth = betterAuth({
|
||||
database: new Pool({
|
||||
connectionString: process.env.DATABASE_URL,
|
||||
}),
|
||||
trustedOrigins: ["money://", "http://localhost:8081"],
|
||||
plugins: [
|
||||
expo(),
|
||||
genericOAuth({
|
||||
config: [
|
||||
{
|
||||
providerId: 'koon-family',
|
||||
clientId: process.env.OAUTH_CLIENT_ID!,
|
||||
clientSecret: process.env.OAUTH_CLIENT_SECRET!,
|
||||
discoveryUrl: process.env.OAUTH_DISCOVERY_URL!,
|
||||
scopes: ["profile", "email"],
|
||||
}
|
||||
]
|
||||
})
|
||||
]
|
||||
});
|
||||
5
api/src/hono.ts
Normal file
5
api/src/hono.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import type { AuthData } from "@money/shared/auth";
|
||||
import { Hono } from "hono";
|
||||
|
||||
export const getHono = () =>
|
||||
new Hono<{ Variables: { auth: AuthData | null } }>();
|
||||
55
api/src/index.ts
Normal file
55
api/src/index.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
import { serve } from "@hono/node-server";
|
||||
import { authDataSchema } from "@money/shared/auth";
|
||||
import { cors } from "hono/cors";
|
||||
import { auth } from "./auth";
|
||||
import { getHono } from "./hono";
|
||||
import { zero } from "./zero";
|
||||
|
||||
const app = getHono();
|
||||
|
||||
app.use(
|
||||
"/api/*",
|
||||
cors({
|
||||
origin: (origin) => origin ?? "",
|
||||
allowMethods: ["POST", "GET", "OPTIONS"],
|
||||
allowHeaders: ["Content-Type", "Authorization"],
|
||||
credentials: true,
|
||||
}),
|
||||
);
|
||||
|
||||
app.on(["GET", "POST"], "/api/auth/*", (c) => auth.handler(c.req.raw));
|
||||
|
||||
app.use("*", async (c, next) => {
|
||||
const authHeader = c.req.raw.headers.get("Authorization");
|
||||
const cookie = authHeader?.split("Bearer ")[1];
|
||||
|
||||
const newHeaders = new Headers(c.req.raw.headers);
|
||||
|
||||
if (cookie) {
|
||||
newHeaders.set("Cookie", cookie);
|
||||
}
|
||||
|
||||
const session = await auth.api.getSession({ headers: newHeaders });
|
||||
|
||||
if (!session) {
|
||||
c.set("auth", null);
|
||||
return next();
|
||||
}
|
||||
c.set("auth", authDataSchema.parse(session));
|
||||
return next();
|
||||
});
|
||||
|
||||
app.route("/api/zero", zero);
|
||||
|
||||
app.get("/api", (c) => c.text("OK"));
|
||||
app.get("/", (c) => c.text("OK"));
|
||||
|
||||
serve(
|
||||
{
|
||||
fetch: app.fetch,
|
||||
port: 3000,
|
||||
},
|
||||
(info) => {
|
||||
console.log(`Server is running on ${info.address}:${info.port}`);
|
||||
},
|
||||
);
|
||||
96
api/src/zero.ts
Normal file
96
api/src/zero.ts
Normal file
@@ -0,0 +1,96 @@
|
||||
import {
|
||||
type ReadonlyJSONValue,
|
||||
type ServerTransaction,
|
||||
withValidation,
|
||||
} from "@rocicorp/zero";
|
||||
import {
|
||||
handleGetQueriesRequest,
|
||||
PushProcessor,
|
||||
ZQLDatabase,
|
||||
} from "@rocicorp/zero/server";
|
||||
import {
|
||||
// createMutators as createMutatorsShared,
|
||||
// isLoggedIn,
|
||||
// type Mutators,
|
||||
queries,
|
||||
schema,
|
||||
type Schema,
|
||||
} from "@money/shared";
|
||||
import type { AuthData } from "@money/shared/auth";
|
||||
// import { auditLogs } from "@zslack/shared/db";
|
||||
// import {
|
||||
// NodePgConnection,
|
||||
// type NodePgZeroTransaction,
|
||||
// } from "drizzle-zero/node-postgres";
|
||||
import crypto from "node:crypto";
|
||||
// import { db } from "./db";
|
||||
import { getHono } from "./hono";
|
||||
|
||||
// type ServerTx = ServerTransaction<Schema, NodePgZeroTransaction<typeof db>>;
|
||||
|
||||
// const processor = new PushProcessor(
|
||||
// new ZQLDatabase(new NodePgConnection(db), schema),
|
||||
// );
|
||||
//
|
||||
// const createMutators = (authData: AuthData | null) => {
|
||||
// const mutators = createMutatorsShared(authData);
|
||||
//
|
||||
// return {
|
||||
// ...mutators,
|
||||
// message: {
|
||||
// ...mutators.message,
|
||||
// async sendMessage(tx: ServerTx, params) {
|
||||
// isLoggedIn(authData);
|
||||
//
|
||||
// await mutators.message.sendMessage(tx, params);
|
||||
//
|
||||
// // we can use the db tx to insert server-only data, like audit logs
|
||||
// await tx.dbTransaction.wrappedTransaction.insert(auditLogs).values({
|
||||
// id: crypto.randomUUID(),
|
||||
// userId: authData.user.id,
|
||||
// action: "sendMessage",
|
||||
// });
|
||||
// },
|
||||
// },
|
||||
// } as const satisfies Mutators;
|
||||
// };
|
||||
|
||||
const zero = getHono()
|
||||
// .post("/mutate", async (c) => {
|
||||
// // get the auth data from betterauth
|
||||
// const authData = c.get("auth");
|
||||
//
|
||||
// const result = await processor.process(createMutators(authData), c.req.raw);
|
||||
//
|
||||
// return c.json(result);
|
||||
// })
|
||||
.post("/get-queries", async (c) => {
|
||||
// get the auth data from betterauth
|
||||
const authData = c.get("auth");
|
||||
|
||||
const result = await handleGetQueriesRequest(
|
||||
(name, args) => ({ query: getQuery(authData, name, args) }),
|
||||
schema,
|
||||
c.req.raw,
|
||||
);
|
||||
|
||||
return c.json(result);
|
||||
});
|
||||
|
||||
const validatedQueries = Object.fromEntries(
|
||||
Object.values(queries).map((q) => [q.queryName, withValidation(q)]),
|
||||
);
|
||||
|
||||
function getQuery(
|
||||
authData: AuthData | null,
|
||||
name: string,
|
||||
args: readonly ReadonlyJSONValue[],
|
||||
) {
|
||||
if (name in validatedQueries) {
|
||||
const q = validatedQueries[name];
|
||||
return q(authData, ...args);
|
||||
}
|
||||
throw new Error(`Unknown query: ${name}`);
|
||||
}
|
||||
|
||||
export { zero };
|
||||
Reference in New Issue
Block a user