feat: Add user to auth.ts function

This commit is contained in:
Wanjohi
2025-10-26 05:56:22 +03:00
parent 752f3e94d0
commit 53390524ff
8 changed files with 116 additions and 31 deletions

View File

@@ -19,6 +19,7 @@
"typescript": "^5"
},
"dependencies": {
"@polar-sh/sdk": "^0.40.1",
"drizzle-orm": "^0.44.6",
"hono": "catalog:",
"ioredis": "^5.8.2",

View File

@@ -1,15 +1,19 @@
import { userTable } from "../user/user.sql.js";
import { pgTable, varchar } from "drizzle-orm/pg-core";
import { pgTable, unique, varchar } from "drizzle-orm/pg-core";
import { id, timestamps, ulid } from "../drizzle/types.js";
export const orgTable = pgTable("organisations", {
...id,
...timestamps,
ownerID: ulid("owner_id")
.references(() => userTable.id, {
onDelete: "cascade",
})
.notNull(),
name: varchar("name", { length: 255 }).unique().notNull(),
slug: varchar("slug", { length: 255 }).unique().notNull(),
});
export const orgTable = pgTable(
"organisations",
{
...id,
...timestamps,
ownerID: ulid("owner_id")
.references(() => userTable.id, {
onDelete: "cascade",
})
.notNull(),
name: varchar("name", { length: 255 }).notNull(),
slug: varchar("slug", { length: 255 }).notNull(),
},
(org) => [unique("idx_organisation_slug").on(org.slug)],
);

View File

@@ -1,5 +1,11 @@
import { z } from "zod/v4";
import { fn } from "../utils/fn.js";
import { userTable } from "./user.sql.js";
import { createID } from "../utils/id.js";
import { Examples } from "../examples.js";
import { Polar } from "../polar/index.js";
import { Database } from "../drizzle/index.js";
import { eq, and, isNotNull } from "drizzle-orm";
export namespace User {
export const Info = z
@@ -8,7 +14,7 @@ export namespace User {
description: "The unique identifier of the user",
example: Examples.User.id,
}),
name: z.string().optional().meta({
name: z.string().nullable().meta({
description: "The full name of the user",
example: Examples.User.name,
}),
@@ -28,4 +34,67 @@ export namespace User {
});
export type Info = z.infer<typeof Info>;
export const create = fn(
Info.omit({ customerID: true }).partial({ id: true }),
async (input) => {
const id = input.id ?? createID("user");
const customerID = await Polar.fromUserEmail(input.email).then(
(z) => z.id,
);
await Database.transaction((tx) =>
tx
.insert(userTable)
.values({
id,
customerID,
name: input.name,
email: input.email,
})
.onConflictDoUpdate({
target: userTable.email,
set: {
timeDeleted: null,
},
}),
);
return id;
},
);
export const fromEmail = fn(Info.shape.email, (email) =>
Database.transaction((tx) =>
tx
.select()
.from(userTable)
.where(
and(eq(userTable.email, email), isNotNull(userTable.timeDeleted)),
)
.then((rows) => rows.map(serialize).at(0)),
),
);
export const fromID = fn(Info.shape.id, (id) =>
Database.transaction((tx) =>
tx
.select()
.from(userTable)
.where(and(eq(userTable.id, id), isNotNull(userTable.timeDeleted)))
.then((rows) => rows.map(serialize).at(0)),
),
);
export function serialize(
input: typeof userTable.$inferSelect,
): z.infer<typeof Info> {
return {
id: input.id,
name: input.name,
email: input.email,
customerID: input.customerID,
};
}
}

View File

@@ -1,10 +1,14 @@
import { id, timestamps } from "../drizzle/types.js";
import { pgTable, varchar } from "drizzle-orm/pg-core";
import { pgTable, varchar, unique } from "drizzle-orm/pg-core";
export const userTable = pgTable("users", {
...id,
...timestamps,
name: varchar("name", { length: 255 }),
email: varchar("email", { length: 255 }).unique().notNull(),
customerID: varchar("customer_id", { length: 255 }).notNull(),
});
export const userTable = pgTable(
"users",
{
...id,
...timestamps,
name: varchar("name", { length: 255 }),
email: varchar("email", { length: 255 }).notNull(),
customerID: varchar("customer_id", { length: 255 }).notNull(),
},
(user) => [unique("idx_user_email").on(user.email)],
);

View File

@@ -3,7 +3,6 @@ import { ulid } from "ulid";
export const prefixes = {
user: "usr",
steam: "stm",
team: "tm",
app: "app",
member: "mbr",
apiSecret: "sec",
@@ -14,7 +13,7 @@ export const prefixes = {
/**
* Generates a unique identifier by concatenating a predefined prefix with a ULID.
*
* Given a key from the predefined prefixes mapping (e.g.,"team", "member", "steam"),
* Given a key from the predefined prefixes mapping (e.g.,"user", "member", "steam"),
* this function retrieves the corresponding prefix and combines it with a ULID using an underscore
* as a separator. The resulting identifier is formatted as "prefix_ulid".
*